1 // Written in the D programming language. 2 3 /** 4 This is a submodule of $(MREF std, math). 5 6 It contains several exponential and logarithm functions. 7 8 Copyright: Copyright The D Language Foundation 2000 - 2011. 9 D implementations of exp, expm1, exp2, log, log10, log1p, and log2 10 functions are based on the CEPHES math library, which is Copyright 11 (C) 2001 Stephen L. Moshier $(LT)steve@moshier.net$(GT) and are 12 incorporated herein by permission of the author. The author reserves 13 the right to distribute this material elsewhere under different 14 copying permissions. These modifications are distributed here under 15 the following terms: 16 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 17 Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston, 18 Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger 19 Source: $(PHOBOSSRC std/math/exponential.d) 20 21 Macros: 22 TABLE_SV = <table border="1" cellpadding="4" cellspacing="0"> 23 <caption>Special Values</caption> 24 $0</table> 25 NAN = $(RED NAN) 26 PLUSMN = ± 27 INFIN = ∞ 28 PLUSMNINF = ±∞ 29 LT = < 30 GT = > 31 */ 32 33 module std.math.exponential; 34 35 import std.traits : isFloatingPoint, isIntegral, isSigned, isUnsigned, Largest, Unqual; 36 37 static import core.math; 38 static import core.stdc.math; 39 40 version (DigitalMars) 41 { 42 version = INLINE_YL2X; // x87 has opcodes for these 43 } 44 45 version (D_InlineAsm_X86) version = InlineAsm_X86_Any; 46 version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; 47 48 version (InlineAsm_X86_Any) version = InlineAsm_X87; 49 version (InlineAsm_X87) 50 { 51 version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC; 52 else static assert(real.mant_dig == 64); 53 } 54 55 version (D_HardFloat) 56 { 57 // FloatingPointControl.clearExceptions() depends on version IeeeFlagsSupport 58 version (IeeeFlagsSupport) version = FloatingPointControlSupport; 59 } 60 61 /** 62 * Compute the value of x $(SUPERSCRIPT n), where n is an integer 63 */ 64 Unqual!F pow(F, G)(F x, G n) @nogc @trusted pure nothrow 65 if (isFloatingPoint!(F) && isIntegral!(G)) 66 { 67 import std.traits : Unsigned; 68 69 real p = 1.0, v = void; 70 Unsigned!(Unqual!G) m = n; 71 72 if (n < 0) 73 { 74 if (n == -1) return 1 / x; 75 76 m = cast(typeof(m))(0 - n); 77 v = p / x; 78 } 79 else 80 { 81 switch (n) 82 { 83 case 0: 84 return 1.0; 85 case 1: 86 return x; 87 case 2: 88 return x * x; 89 default: 90 } 91 92 v = x; 93 } 94 95 while (1) 96 { 97 if (m & 1) 98 p *= v; 99 m >>= 1; 100 if (!m) 101 break; 102 v *= v; 103 } 104 return p; 105 } 106 107 /// 108 @safe pure nothrow @nogc unittest 109 { 110 import std.math.operations : feqrel; 111 112 assert(pow(2.0, 5) == 32.0); 113 assert(pow(1.5, 9).feqrel(38.4433) > 16); 114 assert(pow(real.nan, 2) is real.nan); 115 assert(pow(real.infinity, 2) == real.infinity); 116 } 117 118 @safe pure nothrow @nogc unittest 119 { 120 import std.math.operations : isClose, feqrel; 121 122 // Make sure it instantiates and works properly on immutable values and 123 // with various integer and float types. 124 immutable real x = 46; 125 immutable float xf = x; 126 immutable double xd = x; 127 immutable uint one = 1; 128 immutable ushort two = 2; 129 immutable ubyte three = 3; 130 immutable ulong eight = 8; 131 132 immutable int neg1 = -1; 133 immutable short neg2 = -2; 134 immutable byte neg3 = -3; 135 immutable long neg8 = -8; 136 137 138 assert(pow(x,0) == 1.0); 139 assert(pow(xd,one) == x); 140 assert(pow(xf,two) == x * x); 141 assert(pow(x,three) == x * x * x); 142 assert(pow(x,eight) == (x * x) * (x * x) * (x * x) * (x * x)); 143 144 assert(pow(x, neg1) == 1 / x); 145 146 assert(isClose(pow(xd, neg2), cast(double) (1 / (x * x)), 1e-15)); 147 assert(isClose(pow(xf, neg8), cast(float) (1 / ((x * x) * (x * x) * (x * x) * (x * x))), 1e-15)); 148 149 assert(feqrel(pow(x, neg3), 1 / (x * x * x)) >= real.mant_dig - 1); 150 } 151 152 @safe @nogc nothrow unittest 153 { 154 import std.math.operations : isClose; 155 156 assert(isClose(pow(2.0L, 10L), 1024, 1e-18)); 157 } 158 159 // https://issues.dlang.org/show_bug.cgi?id=21601 160 @safe @nogc nothrow pure unittest 161 { 162 // When reals are large enough the results of pow(b, e) can be 163 // calculated correctly, if b is of type float or double and e is 164 // not too large. 165 static if (real.mant_dig >= 64) 166 { 167 // expected result: 3.790e-42 168 assert(pow(-513645318757045764096.0f, -2) > 0.0); 169 170 // expected result: 3.763915357831797e-309 171 assert(pow(-1.6299717435255677e+154, -2) > 0.0); 172 } 173 } 174 175 @safe @nogc nothrow unittest 176 { 177 import std.math.operations : isClose; 178 import std.math.traits : isInfinity; 179 180 static float f1 = 19100.0f; 181 static float f2 = 0.000012f; 182 183 assert(isClose(pow(f1,9), 3.3829868e+38f)); 184 assert(isInfinity(pow(f1,10))); 185 assert(pow(f2,9) > 0.0f); 186 assert(isClose(pow(f2,10), 0.0f, 0.0, float.min_normal)); 187 188 static double d1 = 21800.0; 189 static double d2 = 0.000012; 190 191 assert(isClose(pow(d1,71), 1.0725339442974e+308)); 192 assert(isInfinity(pow(d1,72))); 193 assert(pow(d2,65) > 0.0f); 194 assert(isClose(pow(d2,66), 0.0, 0.0, double.min_normal)); 195 196 static if (real.mant_dig == 64) // x87 197 { 198 static real r1 = 21950.0L; 199 static real r2 = 0.000011L; 200 201 assert(isClose(pow(r1,1136), 7.4066175654969242752260330529e+4931L)); 202 assert(isInfinity(pow(r1,1137))); 203 assert(pow(r2,998) > 0.0L); 204 assert(isClose(pow(r2,999), 0.0L, 0.0, real.min_normal)); 205 } 206 } 207 208 @safe @nogc nothrow pure unittest 209 { 210 import std.math.operations : isClose; 211 212 enum f1 = 19100.0f; 213 enum f2 = 0.000012f; 214 215 static assert(isClose(pow(f1,9), 3.3829868e+38f)); 216 static assert(pow(f1,10) > float.max); 217 static assert(pow(f2,9) > 0.0f); 218 static assert(isClose(pow(f2,10), 0.0f, 0.0, float.min_normal)); 219 220 enum d1 = 21800.0; 221 enum d2 = 0.000012; 222 223 static assert(isClose(pow(d1,71), 1.0725339442974e+308)); 224 static assert(pow(d1,72) > double.max); 225 static assert(pow(d2,65) > 0.0f); 226 static assert(isClose(pow(d2,66), 0.0, 0.0, double.min_normal)); 227 228 static if (real.mant_dig == 64) // x87 229 { 230 enum r1 = 21950.0L; 231 enum r2 = 0.000011L; 232 233 static assert(isClose(pow(r1,1136), 7.4066175654969242752260330529e+4931L)); 234 static assert(pow(r1,1137) > real.max); 235 static assert(pow(r2,998) > 0.0L); 236 static assert(isClose(pow(r2,999), 0.0L, 0.0, real.min_normal)); 237 } 238 } 239 240 /** 241 * Compute the power of two integral numbers. 242 * 243 * Params: 244 * x = base 245 * n = exponent 246 * 247 * Returns: 248 * x raised to the power of n. If n is negative the result is 1 / pow(x, -n), 249 * which is calculated as integer division with remainder. This may result in 250 * a division by zero error. 251 * 252 * If both x and n are 0, the result is 1. 253 * 254 * Throws: 255 * If x is 0 and n is negative, the result is the same as the result of a 256 * division by zero. 257 */ 258 typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @trusted pure nothrow 259 if (isIntegral!(F) && isIntegral!(G)) 260 { 261 import std.traits : isSigned; 262 263 typeof(return) p, v = void; 264 Unqual!G m = n; 265 266 static if (isSigned!(F)) 267 { 268 if (x == -1) return cast(typeof(return)) (m & 1 ? -1 : 1); 269 } 270 static if (isSigned!(G)) 271 { 272 if (x == 0 && m <= -1) return x / 0; 273 } 274 if (x == 1) return 1; 275 static if (isSigned!(G)) 276 { 277 if (m < 0) return 0; 278 } 279 280 switch (m) 281 { 282 case 0: 283 p = 1; 284 break; 285 286 case 1: 287 p = x; 288 break; 289 290 case 2: 291 p = x * x; 292 break; 293 294 default: 295 v = x; 296 p = 1; 297 while (1) 298 { 299 if (m & 1) 300 p *= v; 301 m >>= 1; 302 if (!m) 303 break; 304 v *= v; 305 } 306 break; 307 } 308 return p; 309 } 310 311 /// 312 @safe pure nothrow @nogc unittest 313 { 314 assert(pow(2, 3) == 8); 315 assert(pow(3, 2) == 9); 316 317 assert(pow(2, 10) == 1_024); 318 assert(pow(2, 20) == 1_048_576); 319 assert(pow(2, 30) == 1_073_741_824); 320 321 assert(pow(0, 0) == 1); 322 323 assert(pow(1, -5) == 1); 324 assert(pow(1, -6) == 1); 325 assert(pow(-1, -5) == -1); 326 assert(pow(-1, -6) == 1); 327 328 assert(pow(-2, 5) == -32); 329 assert(pow(-2, -5) == 0); 330 assert(pow(cast(double) -2, -5) == -0.03125); 331 } 332 333 @safe pure nothrow @nogc unittest 334 { 335 immutable int one = 1; 336 immutable byte two = 2; 337 immutable ubyte three = 3; 338 immutable short four = 4; 339 immutable long ten = 10; 340 341 assert(pow(two, three) == 8); 342 assert(pow(two, ten) == 1024); 343 assert(pow(one, ten) == 1); 344 assert(pow(ten, four) == 10_000); 345 assert(pow(four, 10) == 1_048_576); 346 assert(pow(three, four) == 81); 347 } 348 349 // https://issues.dlang.org/show_bug.cgi?id=7006 350 @safe pure nothrow @nogc unittest 351 { 352 assert(pow(5, -1) == 0); 353 assert(pow(-5, -1) == 0); 354 assert(pow(5, -2) == 0); 355 assert(pow(-5, -2) == 0); 356 assert(pow(-1, int.min) == 1); 357 assert(pow(-2, int.min) == 0); 358 359 assert(pow(4294967290UL,2) == 18446744022169944100UL); 360 assert(pow(0,uint.max) == 0); 361 } 362 363 /**Computes integer to floating point powers.*/ 364 real pow(I, F)(I x, F y) @nogc @trusted pure nothrow 365 if (isIntegral!I && isFloatingPoint!F) 366 { 367 return pow(cast(real) x, cast(Unqual!F) y); 368 } 369 370 /// 371 @safe pure nothrow @nogc unittest 372 { 373 assert(pow(2, 5.0) == 32.0); 374 assert(pow(7, 3.0) == 343.0); 375 assert(pow(2, real.nan) is real.nan); 376 assert(pow(2, real.infinity) == real.infinity); 377 } 378 379 /** 380 * Calculates x$(SUPERSCRIPT y). 381 * 382 * $(TABLE_SV 383 * $(TR $(TH x) $(TH y) $(TH pow(x, y)) 384 * $(TH div 0) $(TH invalid?)) 385 * $(TR $(TD anything) $(TD $(PLUSMN)0.0) $(TD 1.0) 386 * $(TD no) $(TD no) ) 387 * $(TR $(TD |x| $(GT) 1) $(TD +$(INFIN)) $(TD +$(INFIN)) 388 * $(TD no) $(TD no) ) 389 * $(TR $(TD |x| $(LT) 1) $(TD +$(INFIN)) $(TD +0.0) 390 * $(TD no) $(TD no) ) 391 * $(TR $(TD |x| $(GT) 1) $(TD -$(INFIN)) $(TD +0.0) 392 * $(TD no) $(TD no) ) 393 * $(TR $(TD |x| $(LT) 1) $(TD -$(INFIN)) $(TD +$(INFIN)) 394 * $(TD no) $(TD no) ) 395 * $(TR $(TD +$(INFIN)) $(TD $(GT) 0.0) $(TD +$(INFIN)) 396 * $(TD no) $(TD no) ) 397 * $(TR $(TD +$(INFIN)) $(TD $(LT) 0.0) $(TD +0.0) 398 * $(TD no) $(TD no) ) 399 * $(TR $(TD -$(INFIN)) $(TD odd integer $(GT) 0.0) $(TD -$(INFIN)) 400 * $(TD no) $(TD no) ) 401 * $(TR $(TD -$(INFIN)) $(TD $(GT) 0.0, not odd integer) $(TD +$(INFIN)) 402 * $(TD no) $(TD no)) 403 * $(TR $(TD -$(INFIN)) $(TD odd integer $(LT) 0.0) $(TD -0.0) 404 * $(TD no) $(TD no) ) 405 * $(TR $(TD -$(INFIN)) $(TD $(LT) 0.0, not odd integer) $(TD +0.0) 406 * $(TD no) $(TD no) ) 407 * $(TR $(TD $(PLUSMN)1.0) $(TD $(PLUSMN)$(INFIN)) $(TD -$(NAN)) 408 * $(TD no) $(TD yes) ) 409 * $(TR $(TD $(LT) 0.0) $(TD finite, nonintegral) $(TD $(NAN)) 410 * $(TD no) $(TD yes)) 411 * $(TR $(TD $(PLUSMN)0.0) $(TD odd integer $(LT) 0.0) $(TD $(PLUSMNINF)) 412 * $(TD yes) $(TD no) ) 413 * $(TR $(TD $(PLUSMN)0.0) $(TD $(LT) 0.0, not odd integer) $(TD +$(INFIN)) 414 * $(TD yes) $(TD no)) 415 * $(TR $(TD $(PLUSMN)0.0) $(TD odd integer $(GT) 0.0) $(TD $(PLUSMN)0.0) 416 * $(TD no) $(TD no) ) 417 * $(TR $(TD $(PLUSMN)0.0) $(TD $(GT) 0.0, not odd integer) $(TD +0.0) 418 * $(TD no) $(TD no) ) 419 * ) 420 */ 421 Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow 422 if (isFloatingPoint!(F) && isFloatingPoint!(G)) 423 { 424 import core.math : fabs, sqrt; 425 import std.math.traits : isInfinity, isNaN, signbit; 426 427 alias Float = typeof(return); 428 429 static real impl(real x, real y) @nogc pure nothrow 430 { 431 // Special cases. 432 if (isNaN(y)) 433 return y; 434 if (isNaN(x) && y != 0.0) 435 return x; 436 437 // Even if x is NaN. 438 if (y == 0.0) 439 return 1.0; 440 if (y == 1.0) 441 return x; 442 443 if (isInfinity(y)) 444 { 445 if (isInfinity(x)) 446 { 447 if (!signbit(y) && !signbit(x)) 448 return F.infinity; 449 else 450 return F.nan; 451 } 452 else if (fabs(x) > 1) 453 { 454 if (signbit(y)) 455 return +0.0; 456 else 457 return F.infinity; 458 } 459 else if (fabs(x) == 1) 460 { 461 return F.nan; 462 } 463 else // < 1 464 { 465 if (signbit(y)) 466 return F.infinity; 467 else 468 return +0.0; 469 } 470 } 471 if (isInfinity(x)) 472 { 473 if (signbit(x)) 474 { 475 long i = cast(long) y; 476 if (y > 0.0) 477 { 478 if (i == y && i & 1) 479 return -F.infinity; 480 else if (i == y) 481 return F.infinity; 482 else 483 return -F.nan; 484 } 485 else if (y < 0.0) 486 { 487 if (i == y && i & 1) 488 return -0.0; 489 else if (i == y) 490 return +0.0; 491 else 492 return F.nan; 493 } 494 } 495 else 496 { 497 if (y > 0.0) 498 return F.infinity; 499 else if (y < 0.0) 500 return +0.0; 501 } 502 } 503 504 if (x == 0.0) 505 { 506 if (signbit(x)) 507 { 508 long i = cast(long) y; 509 if (y > 0.0) 510 { 511 if (i == y && i & 1) 512 return -0.0; 513 else 514 return +0.0; 515 } 516 else if (y < 0.0) 517 { 518 if (i == y && i & 1) 519 return -F.infinity; 520 else 521 return F.infinity; 522 } 523 } 524 else 525 { 526 if (y > 0.0) 527 return +0.0; 528 else if (y < 0.0) 529 return F.infinity; 530 } 531 } 532 if (x == 1.0) 533 return 1.0; 534 535 if (y >= F.max) 536 { 537 if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) 538 return 0.0; 539 if (x > 1.0 || x < -1.0) 540 return F.infinity; 541 } 542 if (y <= -F.max) 543 { 544 if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) 545 return F.infinity; 546 if (x > 1.0 || x < -1.0) 547 return 0.0; 548 } 549 550 if (x >= F.max) 551 { 552 if (y > 0.0) 553 return F.infinity; 554 else 555 return 0.0; 556 } 557 if (x <= -F.max) 558 { 559 long i = cast(long) y; 560 if (y > 0.0) 561 { 562 if (i == y && i & 1) 563 return -F.infinity; 564 else 565 return F.infinity; 566 } 567 else if (y < 0.0) 568 { 569 if (i == y && i & 1) 570 return -0.0; 571 else 572 return +0.0; 573 } 574 } 575 576 // Integer power of x. 577 long iy = cast(long) y; 578 if (iy == y && fabs(y) < 32_768.0) 579 return pow(x, iy); 580 581 real sign = 1.0; 582 if (x < 0) 583 { 584 // Result is real only if y is an integer 585 // Check for a non-zero fractional part 586 enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L; 587 static if (maxOdd > ulong.max) 588 { 589 // Generic method, for any FP type 590 import std.math.rounding : floor; 591 if (floor(y) != y) 592 return sqrt(x); // Complex result -- create a NaN 593 594 const hy = 0.5 * y; 595 if (floor(hy) != hy) 596 sign = -1.0; 597 } 598 else 599 { 600 // Much faster, if ulong has enough precision 601 const absY = fabs(y); 602 if (absY <= maxOdd) 603 { 604 const uy = cast(ulong) absY; 605 if (uy != absY) 606 return sqrt(x); // Complex result -- create a NaN 607 608 if (uy & 1) 609 sign = -1.0; 610 } 611 } 612 x = -x; 613 } 614 version (INLINE_YL2X) 615 { 616 // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) 617 // TODO: This is not accurate in practice. A fast and accurate 618 // (though complicated) method is described in: 619 // "An efficient rounding boundary test for pow(x, y) 620 // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). 621 return sign * exp2( core.math.yl2x(x, y) ); 622 } 623 else 624 { 625 // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) 626 // TODO: This is not accurate in practice. A fast and accurate 627 // (though complicated) method is described in: 628 // "An efficient rounding boundary test for pow(x, y) 629 // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). 630 Float w = exp2(y * log2(x)); 631 return sign * w; 632 } 633 } 634 return impl(x, y); 635 } 636 637 /// 638 @safe pure nothrow @nogc unittest 639 { 640 import std.math.operations : isClose; 641 642 assert(isClose(pow(2.0, 3.0), 8.0)); 643 assert(isClose(pow(1.5, 10.0), 57.6650390625)); 644 645 // square root of 9 646 assert(isClose(pow(9.0, 0.5), 3.0)); 647 // 10th root of 1024 648 assert(isClose(pow(1024.0, 0.1), 2.0)); 649 650 assert(isClose(pow(-4.0, 3.0), -64.0)); 651 652 // reciprocal of 4 ^^ 2 653 assert(isClose(pow(4.0, -2.0), 0.0625)); 654 // reciprocal of (-2) ^^ 3 655 assert(isClose(pow(-2.0, -3.0), -0.125)); 656 657 assert(isClose(pow(-2.5, 3.0), -15.625)); 658 // reciprocal of 2.5 ^^ 3 659 assert(isClose(pow(2.5, -3.0), 0.064)); 660 // reciprocal of (-2.5) ^^ 3 661 assert(isClose(pow(-2.5, -3.0), -0.064)); 662 663 // reciprocal of square root of 4 664 assert(isClose(pow(4.0, -0.5), 0.5)); 665 666 // per definition 667 assert(isClose(pow(0.0, 0.0), 1.0)); 668 } 669 670 /// 671 @safe pure nothrow @nogc unittest 672 { 673 import std.math.operations : isClose; 674 675 // the result is a complex number 676 // which cannot be represented as floating point number 677 import std.math.traits : isNaN; 678 assert(isNaN(pow(-2.5, -1.5))); 679 680 // use the ^^-operator of std.complex instead 681 import std.complex : complex; 682 auto c1 = complex(-2.5, 0.0); 683 auto c2 = complex(-1.5, 0.0); 684 auto result = c1 ^^ c2; 685 // exact result apparently depends on `real` precision => increased tolerance 686 assert(isClose(result.re, -4.64705438e-17, 2e-4)); 687 assert(isClose(result.im, 2.52982e-1, 2e-4)); 688 } 689 690 @safe pure nothrow @nogc unittest 691 { 692 import std.math.traits : isNaN; 693 694 assert(pow(1.5, real.infinity) == real.infinity); 695 assert(pow(0.5, real.infinity) == 0.0); 696 assert(pow(1.5, -real.infinity) == 0.0); 697 assert(pow(0.5, -real.infinity) == real.infinity); 698 assert(pow(real.infinity, 1.0) == real.infinity); 699 assert(pow(real.infinity, -1.0) == 0.0); 700 assert(pow(real.infinity, real.infinity) == real.infinity); 701 assert(pow(-real.infinity, 1.0) == -real.infinity); 702 assert(pow(-real.infinity, 2.0) == real.infinity); 703 assert(pow(-real.infinity, -1.0) == -0.0); 704 assert(pow(-real.infinity, -2.0) == 0.0); 705 assert(isNaN(pow(1.0, real.infinity))); 706 assert(pow(0.0, -1.0) == real.infinity); 707 assert(pow(real.nan, 0.0) == 1.0); 708 assert(isNaN(pow(real.nan, 3.0))); 709 assert(isNaN(pow(3.0, real.nan))); 710 } 711 712 @safe @nogc nothrow unittest 713 { 714 import std.math.operations : isClose; 715 716 assert(isClose(pow(2.0L, 10.0L), 1024, 1e-18)); 717 } 718 719 @safe pure nothrow @nogc unittest 720 { 721 import std.math.operations : isClose; 722 import std.math.traits : isIdentical, isNaN; 723 import std.math.constants : PI; 724 725 // Test all the special values. These unittests can be run on Windows 726 // by temporarily changing the version (linux) to version (all). 727 immutable float zero = 0; 728 immutable real one = 1; 729 immutable double two = 2; 730 immutable float three = 3; 731 immutable float fnan = float.nan; 732 immutable double dnan = double.nan; 733 immutable real rnan = real.nan; 734 immutable dinf = double.infinity; 735 immutable rninf = -real.infinity; 736 737 assert(pow(fnan, zero) == 1); 738 assert(pow(dnan, zero) == 1); 739 assert(pow(rnan, zero) == 1); 740 741 assert(pow(two, dinf) == double.infinity); 742 assert(isIdentical(pow(0.2f, dinf), +0.0)); 743 assert(pow(0.99999999L, rninf) == real.infinity); 744 assert(isIdentical(pow(1.000000001, rninf), +0.0)); 745 assert(pow(dinf, 0.001) == dinf); 746 assert(isIdentical(pow(dinf, -0.001), +0.0)); 747 assert(pow(rninf, 3.0L) == rninf); 748 assert(pow(rninf, 2.0L) == real.infinity); 749 assert(isIdentical(pow(rninf, -3.0), -0.0)); 750 assert(isIdentical(pow(rninf, -2.0), +0.0)); 751 752 // @@@BUG@@@ somewhere 753 version (OSX) {} else assert(isNaN(pow(one, dinf))); 754 version (OSX) {} else assert(isNaN(pow(-one, dinf))); 755 assert(isNaN(pow(-0.2, PI))); 756 // boundary cases. Note that epsilon == 2^^-n for some n, 757 // so 1/epsilon == 2^^n is always even. 758 assert(pow(-1.0L, 1/real.epsilon - 1.0L) == -1.0L); 759 assert(pow(-1.0L, 1/real.epsilon) == 1.0L); 760 assert(isNaN(pow(-1.0L, 1/real.epsilon-0.5L))); 761 assert(isNaN(pow(-1.0L, -1/real.epsilon+0.5L))); 762 763 assert(pow(0.0, -3.0) == double.infinity); 764 assert(pow(-0.0, -3.0) == -double.infinity); 765 assert(pow(0.0, -PI) == double.infinity); 766 assert(pow(-0.0, -PI) == double.infinity); 767 assert(isIdentical(pow(0.0, 5.0), 0.0)); 768 assert(isIdentical(pow(-0.0, 5.0), -0.0)); 769 assert(isIdentical(pow(0.0, 6.0), 0.0)); 770 assert(isIdentical(pow(-0.0, 6.0), 0.0)); 771 772 // https://issues.dlang.org/show_bug.cgi?id=14786 fixed 773 immutable real maxOdd = pow(2.0L, real.mant_dig) - 1.0L; 774 assert(pow(-1.0L, maxOdd) == -1.0L); 775 assert(pow(-1.0L, -maxOdd) == -1.0L); 776 assert(pow(-1.0L, maxOdd + 1.0L) == 1.0L); 777 assert(pow(-1.0L, -maxOdd + 1.0L) == 1.0L); 778 assert(pow(-1.0L, maxOdd - 1.0L) == 1.0L); 779 assert(pow(-1.0L, -maxOdd - 1.0L) == 1.0L); 780 781 // Now, actual numbers. 782 assert(isClose(pow(two, three), 8.0)); 783 assert(isClose(pow(two, -2.5), 0.1767766953)); 784 785 // Test integer to float power. 786 immutable uint twoI = 2; 787 assert(isClose(pow(twoI, three), 8.0)); 788 } 789 790 // https://issues.dlang.org/show_bug.cgi?id=20508 791 @safe pure nothrow @nogc unittest 792 { 793 import std.math.traits : isNaN; 794 795 assert(isNaN(pow(-double.infinity, 0.5))); 796 797 assert(isNaN(pow(-real.infinity, real.infinity))); 798 assert(isNaN(pow(-real.infinity, -real.infinity))); 799 assert(isNaN(pow(-real.infinity, 1.234))); 800 assert(isNaN(pow(-real.infinity, -0.751))); 801 assert(pow(-real.infinity, 0.0) == 1.0); 802 } 803 804 /** Computes the value of a positive integer `x`, raised to the power `n`, modulo `m`. 805 * 806 * Params: 807 * x = base 808 * n = exponent 809 * m = modulus 810 * 811 * Returns: 812 * `x` to the power `n`, modulo `m`. 813 * The return type is the largest of `x`'s and `m`'s type. 814 * 815 * The function requires that all values have unsigned types. 816 */ 817 Unqual!(Largest!(F, H)) powmod(F, G, H)(F x, G n, H m) 818 if (isUnsigned!F && isUnsigned!G && isUnsigned!H) 819 { 820 import std.meta : AliasSeq; 821 822 alias T = Unqual!(Largest!(F, H)); 823 static if (T.sizeof <= 4) 824 { 825 alias DoubleT = AliasSeq!(void, ushort, uint, void, ulong)[T.sizeof]; 826 } 827 828 static T mulmod(T a, T b, T c) 829 { 830 static if (T.sizeof == 8) 831 { 832 static T addmod(T a, T b, T c) 833 { 834 b = c - b; 835 if (a >= b) 836 return a - b; 837 else 838 return c - b + a; 839 } 840 841 T result = 0, tmp; 842 843 b %= c; 844 while (a > 0) 845 { 846 if (a & 1) 847 result = addmod(result, b, c); 848 849 a >>= 1; 850 b = addmod(b, b, c); 851 } 852 853 return result; 854 } 855 else 856 { 857 DoubleT result = cast(DoubleT) (cast(DoubleT) a * cast(DoubleT) b); 858 return result % c; 859 } 860 } 861 862 T base = x, result = 1, modulus = m; 863 Unqual!G exponent = n; 864 865 while (exponent > 0) 866 { 867 if (exponent & 1) 868 result = mulmod(result, base, modulus); 869 870 base = mulmod(base, base, modulus); 871 exponent >>= 1; 872 } 873 874 return result; 875 } 876 877 /// 878 @safe pure nothrow @nogc unittest 879 { 880 assert(powmod(1U, 10U, 3U) == 1); 881 assert(powmod(3U, 2U, 6U) == 3); 882 assert(powmod(5U, 5U, 15U) == 5); 883 assert(powmod(2U, 3U, 5U) == 3); 884 assert(powmod(2U, 4U, 5U) == 1); 885 assert(powmod(2U, 5U, 5U) == 2); 886 } 887 888 @safe pure nothrow @nogc unittest 889 { 890 ulong a = 18446744073709551615u, b = 20u, c = 18446744073709551610u; 891 assert(powmod(a, b, c) == 95367431640625u); 892 a = 100; b = 7919; c = 18446744073709551557u; 893 assert(powmod(a, b, c) == 18223853583554725198u); 894 a = 117; b = 7919; c = 18446744073709551557u; 895 assert(powmod(a, b, c) == 11493139548346411394u); 896 a = 134; b = 7919; c = 18446744073709551557u; 897 assert(powmod(a, b, c) == 10979163786734356774u); 898 a = 151; b = 7919; c = 18446744073709551557u; 899 assert(powmod(a, b, c) == 7023018419737782840u); 900 a = 168; b = 7919; c = 18446744073709551557u; 901 assert(powmod(a, b, c) == 58082701842386811u); 902 a = 185; b = 7919; c = 18446744073709551557u; 903 assert(powmod(a, b, c) == 17423478386299876798u); 904 a = 202; b = 7919; c = 18446744073709551557u; 905 assert(powmod(a, b, c) == 5522733478579799075u); 906 a = 219; b = 7919; c = 18446744073709551557u; 907 assert(powmod(a, b, c) == 15230218982491623487u); 908 a = 236; b = 7919; c = 18446744073709551557u; 909 assert(powmod(a, b, c) == 5198328724976436000u); 910 911 a = 0; b = 7919; c = 18446744073709551557u; 912 assert(powmod(a, b, c) == 0); 913 a = 123; b = 0; c = 18446744073709551557u; 914 assert(powmod(a, b, c) == 1); 915 916 immutable ulong a1 = 253, b1 = 7919, c1 = 18446744073709551557u; 917 assert(powmod(a1, b1, c1) == 3883707345459248860u); 918 919 uint x = 100 ,y = 7919, z = 1844674407u; 920 assert(powmod(x, y, z) == 1613100340u); 921 x = 134; y = 7919; z = 1844674407u; 922 assert(powmod(x, y, z) == 734956622u); 923 x = 151; y = 7919; z = 1844674407u; 924 assert(powmod(x, y, z) == 1738696945u); 925 x = 168; y = 7919; z = 1844674407u; 926 assert(powmod(x, y, z) == 1247580927u); 927 x = 185; y = 7919; z = 1844674407u; 928 assert(powmod(x, y, z) == 1293855176u); 929 x = 202; y = 7919; z = 1844674407u; 930 assert(powmod(x, y, z) == 1566963682u); 931 x = 219; y = 7919; z = 1844674407u; 932 assert(powmod(x, y, z) == 181227807u); 933 x = 236; y = 7919; z = 1844674407u; 934 assert(powmod(x, y, z) == 217988321u); 935 x = 253; y = 7919; z = 1844674407u; 936 assert(powmod(x, y, z) == 1588843243u); 937 938 x = 0; y = 7919; z = 184467u; 939 assert(powmod(x, y, z) == 0); 940 x = 123; y = 0; z = 1844674u; 941 assert(powmod(x, y, z) == 1); 942 943 immutable ubyte x1 = 117; 944 immutable uint y1 = 7919; 945 immutable uint z1 = 1844674407u; 946 auto res = powmod(x1, y1, z1); 947 assert(is(typeof(res) == uint)); 948 assert(res == 9479781u); 949 950 immutable ushort x2 = 123; 951 immutable uint y2 = 203; 952 immutable ubyte z2 = 113; 953 auto res2 = powmod(x2, y2, z2); 954 assert(is(typeof(res2) == ushort)); 955 assert(res2 == 42u); 956 } 957 958 /** 959 * Calculates e$(SUPERSCRIPT x). 960 * 961 * $(TABLE_SV 962 * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)) ) 963 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) 964 * $(TR $(TD -$(INFIN)) $(TD +0.0) ) 965 * $(TR $(TD $(NAN)) $(TD $(NAN)) ) 966 * ) 967 */ 968 pragma(inline, true) 969 real exp(real x) @trusted pure nothrow @nogc // TODO: @safe 970 { 971 version (InlineAsm_X87) 972 { 973 import std.math.constants : LOG2E; 974 975 // e^^x = 2^^(LOG2E*x) 976 // (This is valid because the overflow & underflow limits for exp 977 // and exp2 are so similar). 978 if (!__ctfe) 979 return exp2Asm(LOG2E*x); 980 } 981 return expImpl(x); 982 } 983 984 /// ditto 985 pragma(inline, true) 986 double exp(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) exp(cast(real) x) : expImpl(x); } 987 988 /// ditto 989 pragma(inline, true) 990 float exp(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) exp(cast(real) x) : expImpl(x); } 991 992 /// 993 @safe unittest 994 { 995 import std.math.operations : feqrel; 996 import std.math.constants : E; 997 998 assert(exp(0.0) == 1.0); 999 assert(exp(3.0).feqrel(E * E * E) > 16); 1000 } 1001 1002 private T expImpl(T)(T x) @safe pure nothrow @nogc 1003 { 1004 import std.math : floatTraits, RealFormat; 1005 import std.math.traits : isNaN; 1006 import std.math.rounding : floor; 1007 import std.math.algebraic : poly; 1008 import std.math.constants : LOG2E; 1009 1010 alias F = floatTraits!T; 1011 static if (F.realFormat == RealFormat.ieeeSingle) 1012 { 1013 static immutable T[6] P = [ 1014 5.0000001201E-1, 1015 1.6666665459E-1, 1016 4.1665795894E-2, 1017 8.3334519073E-3, 1018 1.3981999507E-3, 1019 1.9875691500E-4, 1020 ]; 1021 1022 enum T C1 = 0.693359375; 1023 enum T C2 = -2.12194440e-4; 1024 1025 // Overflow and Underflow limits. 1026 enum T OF = 88.72283905206835; 1027 enum T UF = -103.278929903431851103; // ln(2^-149) 1028 } 1029 else static if (F.realFormat == RealFormat.ieeeDouble) 1030 { 1031 // Coefficients for exp(x) 1032 static immutable T[3] P = [ 1033 9.99999999999999999910E-1L, 1034 3.02994407707441961300E-2L, 1035 1.26177193074810590878E-4L, 1036 ]; 1037 static immutable T[4] Q = [ 1038 2.00000000000000000009E0L, 1039 2.27265548208155028766E-1L, 1040 2.52448340349684104192E-3L, 1041 3.00198505138664455042E-6L, 1042 ]; 1043 1044 // C1 + C2 = LN2. 1045 enum T C1 = 6.93145751953125E-1; 1046 enum T C2 = 1.42860682030941723212E-6; 1047 1048 // Overflow and Underflow limits. 1049 enum T OF = 7.09782712893383996732E2; // ln((1-2^-53) * 2^1024) 1050 enum T UF = -7.451332191019412076235E2; // ln(2^-1075) 1051 } 1052 else static if (F.realFormat == RealFormat.ieeeExtended || 1053 F.realFormat == RealFormat.ieeeExtended53) 1054 { 1055 // Coefficients for exp(x) 1056 static immutable T[3] P = [ 1057 9.9999999999999999991025E-1L, 1058 3.0299440770744196129956E-2L, 1059 1.2617719307481059087798E-4L, 1060 ]; 1061 static immutable T[4] Q = [ 1062 2.0000000000000000000897E0L, 1063 2.2726554820815502876593E-1L, 1064 2.5244834034968410419224E-3L, 1065 3.0019850513866445504159E-6L, 1066 ]; 1067 1068 // C1 + C2 = LN2. 1069 enum T C1 = 6.9314575195312500000000E-1L; 1070 enum T C2 = 1.4286068203094172321215E-6L; 1071 1072 // Overflow and Underflow limits. 1073 enum T OF = 1.1356523406294143949492E4L; // ln((1-2^-64) * 2^16384) 1074 enum T UF = -1.13994985314888605586758E4L; // ln(2^-16446) 1075 } 1076 else static if (F.realFormat == RealFormat.ieeeQuadruple) 1077 { 1078 // Coefficients for exp(x) - 1 1079 static immutable T[5] P = [ 1080 9.999999999999999999999999999999999998502E-1L, 1081 3.508710990737834361215404761139478627390E-2L, 1082 2.708775201978218837374512615596512792224E-4L, 1083 6.141506007208645008909088812338454698548E-7L, 1084 3.279723985560247033712687707263393506266E-10L 1085 ]; 1086 static immutable T[6] Q = [ 1087 2.000000000000000000000000000000000000150E0, 1088 2.368408864814233538909747618894558968880E-1L, 1089 3.611828913847589925056132680618007270344E-3L, 1090 1.504792651814944826817779302637284053660E-5L, 1091 1.771372078166251484503904874657985291164E-8L, 1092 2.980756652081995192255342779918052538681E-12L 1093 ]; 1094 1095 // C1 + C2 = LN2. 1096 enum T C1 = 6.93145751953125E-1L; 1097 enum T C2 = 1.428606820309417232121458176568075500134E-6L; 1098 1099 // Overflow and Underflow limits. 1100 enum T OF = 1.135583025911358400418251384584930671458833e4L; 1101 enum T UF = -1.143276959615573793352782661133116431383730e4L; 1102 } 1103 else 1104 static assert(0, "Not implemented for this architecture"); 1105 1106 // Special cases. 1107 if (isNaN(x)) 1108 return x; 1109 if (x > OF) 1110 return real.infinity; 1111 if (x < UF) 1112 return 0.0; 1113 1114 // Express: e^^x = e^^g * 2^^n 1115 // = e^^g * e^^(n * LOG2E) 1116 // = e^^(g + n * LOG2E) 1117 T xx = floor((cast(T) LOG2E) * x + cast(T) 0.5); 1118 const int n = cast(int) xx; 1119 x -= xx * C1; 1120 x -= xx * C2; 1121 1122 static if (F.realFormat == RealFormat.ieeeSingle) 1123 { 1124 xx = x * x; 1125 x = poly(x, P) * xx + x + 1.0f; 1126 } 1127 else 1128 { 1129 // Rational approximation for exponential of the fractional part: 1130 // e^^x = 1 + 2x P(x^^2) / (Q(x^^2) - P(x^^2)) 1131 xx = x * x; 1132 const T px = x * poly(xx, P); 1133 x = px / (poly(xx, Q) - px); 1134 x = (cast(T) 1.0) + (cast(T) 2.0) * x; 1135 } 1136 1137 // Scale by power of 2. 1138 x = core.math.ldexp(x, n); 1139 1140 return x; 1141 } 1142 1143 @safe @nogc nothrow unittest 1144 { 1145 import std.math : floatTraits, RealFormat; 1146 import std.math.operations : NaN, feqrel, isClose; 1147 import std.math.constants : E; 1148 import std.math.traits : isIdentical; 1149 import std.math.algebraic : abs; 1150 1151 version (IeeeFlagsSupport) import std.math.hardware : IeeeFlags, resetIeeeFlags, ieeeFlags; 1152 version (FloatingPointControlSupport) 1153 { 1154 import std.math.hardware : FloatingPointControl; 1155 1156 FloatingPointControl ctrl; 1157 if (FloatingPointControl.hasExceptionTraps) 1158 ctrl.disableExceptions(FloatingPointControl.allExceptions); 1159 ctrl.rounding = FloatingPointControl.roundToNearest; 1160 } 1161 1162 static void testExp(T)() 1163 { 1164 enum realFormat = floatTraits!T.realFormat; 1165 static if (realFormat == RealFormat.ieeeQuadruple) 1166 { 1167 static immutable T[2][] exptestpoints = 1168 [ // x exp(x) 1169 [ 1.0L, E ], 1170 [ 0.5L, 0x1.a61298e1e069bc972dfefab6df34p+0L ], 1171 [ 3.0L, E*E*E ], 1172 [ 0x1.6p+13L, 0x1.6e509d45728655cdb4840542acb5p+16250L ], // near overflow 1173 [ 0x1.7p+13L, T.infinity ], // close overflow 1174 [ 0x1p+80L, T.infinity ], // far overflow 1175 [ T.infinity, T.infinity ], 1176 [-0x1.18p+13L, 0x1.5e4bf54b4807034ea97fef0059a6p-12927L ], // near underflow 1177 [-0x1.625p+13L, 0x1.a6bd68a39d11fec3a250cd97f524p-16358L ], // ditto 1178 [-0x1.62dafp+13L, 0x0.cb629e9813b80ed4d639e875be6cp-16382L ], // near underflow - subnormal 1179 [-0x1.6549p+13L, 0x0.0000000000000000000000000001p-16382L ], // ditto 1180 [-0x1.655p+13L, 0 ], // close underflow 1181 [-0x1p+30L, 0 ], // far underflow 1182 ]; 1183 } 1184 else static if (realFormat == RealFormat.ieeeExtended || 1185 realFormat == RealFormat.ieeeExtended53) 1186 { 1187 static immutable T[2][] exptestpoints = 1188 [ // x exp(x) 1189 [ 1.0L, E ], 1190 [ 0.5L, 0x1.a61298e1e069bc97p+0L ], 1191 [ 3.0L, E*E*E ], 1192 [ 0x1.1p+13L, 0x1.29aeffefc8ec645p+12557L ], // near overflow 1193 [ 0x1.7p+13L, T.infinity ], // close overflow 1194 [ 0x1p+80L, T.infinity ], // far overflow 1195 [ T.infinity, T.infinity ], 1196 [-0x1.18p+13L, 0x1.5e4bf54b4806db9p-12927L ], // near underflow 1197 [-0x1.625p+13L, 0x1.a6bd68a39d11f35cp-16358L ], // ditto 1198 [-0x1.62dafp+13L, 0x1.96c53d30277021dp-16383L ], // near underflow - subnormal 1199 [-0x1.643p+13L, 0x1p-16444L ], // ditto 1200 [-0x1.645p+13L, 0 ], // close underflow 1201 [-0x1p+30L, 0 ], // far underflow 1202 ]; 1203 } 1204 else static if (realFormat == RealFormat.ieeeDouble) 1205 { 1206 static immutable T[2][] exptestpoints = 1207 [ // x, exp(x) 1208 [ 1.0L, E ], 1209 [ 0.5L, 0x1.a61298e1e069cp+0L ], 1210 [ 3.0L, E*E*E ], 1211 [ 0x1.6p+9L, 0x1.93bf4ec282efbp+1015L ], // near overflow 1212 [ 0x1.7p+9L, T.infinity ], // close overflow 1213 [ 0x1p+80L, T.infinity ], // far overflow 1214 [ T.infinity, T.infinity ], 1215 [-0x1.6p+9L, 0x1.44a3824e5285fp-1016L ], // near underflow 1216 [-0x1.64p+9L, 0x0.06f84920bb2d4p-1022L ], // near underflow - subnormal 1217 [-0x1.743p+9L, 0x0.0000000000001p-1022L ], // ditto 1218 [-0x1.8p+9L, 0 ], // close underflow 1219 [-0x1p+30L, 0 ], // far underflow 1220 ]; 1221 } 1222 else static if (realFormat == RealFormat.ieeeSingle) 1223 { 1224 static immutable T[2][] exptestpoints = 1225 [ // x, exp(x) 1226 [ 1.0L, E ], 1227 [ 0.5L, 0x1.a61299p+0L ], 1228 [ 3.0L, E*E*E ], 1229 [ 0x1.62p+6L, 0x1.99b988p+127L ], // near overflow 1230 [ 0x1.7p+6L, T.infinity ], // close overflow 1231 [ 0x1p+80L, T.infinity ], // far overflow 1232 [ T.infinity, T.infinity ], 1233 [-0x1.5cp+6L, 0x1.666d0ep-126L ], // near underflow 1234 [-0x1.7p+6L, 0x0.026a42p-126L ], // near underflow - subnormal 1235 [-0x1.9cp+6L, 0x0.000002p-126L ], // ditto 1236 [-0x1.ap+6L, 0 ], // close underflow 1237 [-0x1p+30L, 0 ], // far underflow 1238 ]; 1239 } 1240 else 1241 static assert(0, "No exp() tests for real type!"); 1242 1243 const minEqualMantissaBits = T.mant_dig - 2; 1244 T x; 1245 version (IeeeFlagsSupport) IeeeFlags f; 1246 foreach (ref pair; exptestpoints) 1247 { 1248 version (IeeeFlagsSupport) resetIeeeFlags(); 1249 x = exp(pair[0]); 1250 //printf("exp(%La) = %La, should be %La\n", cast(real) pair[0], cast(real) x, cast(real) pair[1]); 1251 assert(feqrel(x, pair[1]) >= minEqualMantissaBits); 1252 } 1253 1254 // Ideally, exp(0) would not set the inexact flag. 1255 // Unfortunately, fldl2e sets it! 1256 // So it's not realistic to avoid setting it. 1257 assert(exp(cast(T) 0.0) == 1.0); 1258 1259 // NaN propagation. Doesn't set flags, bcos was already NaN. 1260 version (IeeeFlagsSupport) 1261 { 1262 resetIeeeFlags(); 1263 x = exp(T.nan); 1264 f = ieeeFlags; 1265 assert(isIdentical(abs(x), T.nan)); 1266 assert(f.flags == 0); 1267 1268 resetIeeeFlags(); 1269 x = exp(-T.nan); 1270 f = ieeeFlags; 1271 assert(isIdentical(abs(x), T.nan)); 1272 assert(f.flags == 0); 1273 } 1274 else 1275 { 1276 x = exp(T.nan); 1277 assert(isIdentical(abs(x), T.nan)); 1278 1279 x = exp(-T.nan); 1280 assert(isIdentical(abs(x), T.nan)); 1281 } 1282 1283 x = exp(NaN(0x123)); 1284 assert(isIdentical(x, NaN(0x123))); 1285 } 1286 1287 import std.meta : AliasSeq; 1288 foreach (T; AliasSeq!(real, double, float)) 1289 testExp!T(); 1290 1291 // High resolution test (verified against GNU MPFR/Mathematica). 1292 assert(exp(0.5L) == 0x1.A612_98E1_E069_BC97_2DFE_FAB6_DF34p+0L); 1293 1294 assert(isClose(exp(3.0L), E * E * E, real.sizeof > double.sizeof ? 1e-15 : 1e-14)); 1295 } 1296 1297 /** 1298 * Calculates the value of the natural logarithm base (e) 1299 * raised to the power of x, minus 1. 1300 * 1301 * For very small x, expm1(x) is more accurate 1302 * than exp(x)-1. 1303 * 1304 * $(TABLE_SV 1305 * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)-1) ) 1306 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) ) 1307 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) 1308 * $(TR $(TD -$(INFIN)) $(TD -1.0) ) 1309 * $(TR $(TD $(NAN)) $(TD $(NAN)) ) 1310 * ) 1311 */ 1312 pragma(inline, true) 1313 real expm1(real x) @trusted pure nothrow @nogc // TODO: @safe 1314 { 1315 version (InlineAsm_X87) 1316 { 1317 if (!__ctfe) 1318 return expm1Asm(x); 1319 } 1320 return expm1Impl(x); 1321 } 1322 1323 /// ditto 1324 pragma(inline, true) 1325 double expm1(double x) @safe pure nothrow @nogc 1326 { 1327 return __ctfe ? cast(double) expm1(cast(real) x) : expm1Impl(x); 1328 } 1329 1330 /// ditto 1331 pragma(inline, true) 1332 float expm1(float x) @safe pure nothrow @nogc 1333 { 1334 // no single-precision version in Cephes => use double precision 1335 return __ctfe ? cast(float) expm1(cast(real) x) : cast(float) expm1Impl(cast(double) x); 1336 } 1337 1338 /// 1339 @safe unittest 1340 { 1341 import std.math.traits : isIdentical; 1342 import std.math.operations : feqrel; 1343 1344 assert(isIdentical(expm1(0.0), 0.0)); 1345 assert(expm1(1.0).feqrel(1.71828) > 16); 1346 assert(expm1(2.0).feqrel(6.3890) > 16); 1347 } 1348 1349 version (InlineAsm_X87) 1350 private real expm1Asm(real x) @trusted pure nothrow @nogc 1351 { 1352 version (X86) 1353 { 1354 enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 1355 asm pure nothrow @nogc 1356 { 1357 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant. 1358 * Author: Don Clugston. 1359 * 1360 * expm1(x) = 2^^(rndint(y))* 2^^(y-rndint(y)) - 1 where y = LN2*x. 1361 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^^(rndint(y)) 1362 * and 2ym1 = (2^^(y-rndint(y))-1). 1363 * If 2rndy < 0.5*real.epsilon, result is -1. 1364 * Implementation is otherwise the same as for exp2() 1365 */ 1366 naked; 1367 fld real ptr [ESP+4] ; // x 1368 mov AX, [ESP+4+8]; // AX = exponent and sign 1369 sub ESP, 12+8; // Create scratch space on the stack 1370 // [ESP,ESP+2] = scratchint 1371 // [ESP+4..+6, +8..+10, +10] = scratchreal 1372 // set scratchreal mantissa = 1.0 1373 mov dword ptr [ESP+8], 0; 1374 mov dword ptr [ESP+8+4], 0x80000000; 1375 and AX, 0x7FFF; // drop sign bit 1376 cmp AX, 0x401D; // avoid InvalidException in fist 1377 jae L_extreme; 1378 fldl2e; 1379 fmulp ST(1), ST; // y = x*log2(e) 1380 fist dword ptr [ESP]; // scratchint = rndint(y) 1381 fisub dword ptr [ESP]; // y - rndint(y) 1382 // and now set scratchreal exponent 1383 mov EAX, [ESP]; 1384 add EAX, 0x3fff; 1385 jle short L_largenegative; 1386 cmp EAX,0x8000; 1387 jge short L_largepositive; 1388 mov [ESP+8+8],AX; 1389 f2xm1; // 2ym1 = 2^^(y-rndint(y)) -1 1390 fld real ptr [ESP+8] ; // 2rndy = 2^^rndint(y) 1391 fmul ST(1), ST; // ST=2rndy, ST(1)=2rndy*2ym1 1392 fld1; 1393 fsubp ST(1), ST; // ST = 2rndy-1, ST(1) = 2rndy * 2ym1 - 1 1394 faddp ST(1), ST; // ST = 2rndy * 2ym1 + 2rndy - 1 1395 add ESP,12+8; 1396 ret PARAMSIZE; 1397 1398 L_extreme: // Extreme exponent. X is very large positive, very 1399 // large negative, infinity, or NaN. 1400 fxam; 1401 fstsw AX; 1402 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1403 jz L_was_nan; // if x is NaN, returns x 1404 test AX, 0x0200; 1405 jnz L_largenegative; 1406 L_largepositive: 1407 // Set scratchreal = real.max. 1408 // squaring it will create infinity, and set overflow flag. 1409 mov word ptr [ESP+8+8], 0x7FFE; 1410 fstp ST(0); 1411 fld real ptr [ESP+8]; // load scratchreal 1412 fmul ST(0), ST; // square it, to create havoc! 1413 L_was_nan: 1414 add ESP,12+8; 1415 ret PARAMSIZE; 1416 L_largenegative: 1417 fstp ST(0); 1418 fld1; 1419 fchs; // return -1. Underflow flag is not set. 1420 add ESP,12+8; 1421 ret PARAMSIZE; 1422 } 1423 } 1424 else version (X86_64) 1425 { 1426 asm pure nothrow @nogc 1427 { 1428 naked; 1429 } 1430 version (Win64) 1431 { 1432 asm pure nothrow @nogc 1433 { 1434 fld real ptr [RCX]; // x 1435 mov AX,[RCX+8]; // AX = exponent and sign 1436 } 1437 } 1438 else 1439 { 1440 asm pure nothrow @nogc 1441 { 1442 fld real ptr [RSP+8]; // x 1443 mov AX,[RSP+8+8]; // AX = exponent and sign 1444 } 1445 } 1446 asm pure nothrow @nogc 1447 { 1448 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant. 1449 * Author: Don Clugston. 1450 * 1451 * expm1(x) = 2^(rndint(y))* 2^(y-rndint(y)) - 1 where y = LN2*x. 1452 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^(rndint(y)) 1453 * and 2ym1 = (2^(y-rndint(y))-1). 1454 * If 2rndy < 0.5*real.epsilon, result is -1. 1455 * Implementation is otherwise the same as for exp2() 1456 */ 1457 sub RSP, 24; // Create scratch space on the stack 1458 // [RSP,RSP+2] = scratchint 1459 // [RSP+4..+6, +8..+10, +10] = scratchreal 1460 // set scratchreal mantissa = 1.0 1461 mov dword ptr [RSP+8], 0; 1462 mov dword ptr [RSP+8+4], 0x80000000; 1463 and AX, 0x7FFF; // drop sign bit 1464 cmp AX, 0x401D; // avoid InvalidException in fist 1465 jae L_extreme; 1466 fldl2e; 1467 fmul ; // y = x*log2(e) 1468 fist dword ptr [RSP]; // scratchint = rndint(y) 1469 fisub dword ptr [RSP]; // y - rndint(y) 1470 // and now set scratchreal exponent 1471 mov EAX, [RSP]; 1472 add EAX, 0x3fff; 1473 jle short L_largenegative; 1474 cmp EAX,0x8000; 1475 jge short L_largepositive; 1476 mov [RSP+8+8],AX; 1477 f2xm1; // 2^(y-rndint(y)) -1 1478 fld real ptr [RSP+8] ; // 2^rndint(y) 1479 fmul ST(1), ST; 1480 fld1; 1481 fsubp ST(1), ST; 1482 fadd; 1483 add RSP,24; 1484 ret; 1485 1486 L_extreme: // Extreme exponent. X is very large positive, very 1487 // large negative, infinity, or NaN. 1488 fxam; 1489 fstsw AX; 1490 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1491 jz L_was_nan; // if x is NaN, returns x 1492 test AX, 0x0200; 1493 jnz L_largenegative; 1494 L_largepositive: 1495 // Set scratchreal = real.max. 1496 // squaring it will create infinity, and set overflow flag. 1497 mov word ptr [RSP+8+8], 0x7FFE; 1498 fstp ST(0); 1499 fld real ptr [RSP+8]; // load scratchreal 1500 fmul ST(0), ST; // square it, to create havoc! 1501 L_was_nan: 1502 add RSP,24; 1503 ret; 1504 1505 L_largenegative: 1506 fstp ST(0); 1507 fld1; 1508 fchs; // return -1. Underflow flag is not set. 1509 add RSP,24; 1510 ret; 1511 } 1512 } 1513 else 1514 static assert(0); 1515 } 1516 1517 private T expm1Impl(T)(T x) @safe pure nothrow @nogc 1518 { 1519 import std.math : floatTraits, RealFormat; 1520 import std.math.rounding : floor; 1521 import std.math.algebraic : poly; 1522 import std.math.constants : LN2; 1523 1524 // Coefficients for exp(x) - 1 and overflow/underflow limits. 1525 enum realFormat = floatTraits!T.realFormat; 1526 static if (realFormat == RealFormat.ieeeQuadruple) 1527 { 1528 static immutable T[8] P = [ 1529 2.943520915569954073888921213330863757240E8L, 1530 -5.722847283900608941516165725053359168840E7L, 1531 8.944630806357575461578107295909719817253E6L, 1532 -7.212432713558031519943281748462837065308E5L, 1533 4.578962475841642634225390068461943438441E4L, 1534 -1.716772506388927649032068540558788106762E3L, 1535 4.401308817383362136048032038528753151144E1L, 1536 -4.888737542888633647784737721812546636240E-1L 1537 ]; 1538 1539 static immutable T[9] Q = [ 1540 1.766112549341972444333352727998584753865E9L, 1541 -7.848989743695296475743081255027098295771E8L, 1542 1.615869009634292424463780387327037251069E8L, 1543 -2.019684072836541751428967854947019415698E7L, 1544 1.682912729190313538934190635536631941751E6L, 1545 -9.615511549171441430850103489315371768998E4L, 1546 3.697714952261803935521187272204485251835E3L, 1547 -8.802340681794263968892934703309274564037E1L, 1548 1.0 1549 ]; 1550 1551 enum T OF = 1.1356523406294143949491931077970764891253E4L; 1552 enum T UF = -1.143276959615573793352782661133116431383730e4L; 1553 } 1554 else static if (realFormat == RealFormat.ieeeExtended) 1555 { 1556 static immutable T[5] P = [ 1557 -1.586135578666346600772998894928250240826E4L, 1558 2.642771505685952966904660652518429479531E3L, 1559 -3.423199068835684263987132888286791620673E2L, 1560 1.800826371455042224581246202420972737840E1L, 1561 -5.238523121205561042771939008061958820811E-1L, 1562 ]; 1563 static immutable T[6] Q = [ 1564 -9.516813471998079611319047060563358064497E4L, 1565 3.964866271411091674556850458227710004570E4L, 1566 -7.207678383830091850230366618190187434796E3L, 1567 7.206038318724600171970199625081491823079E2L, 1568 -4.002027679107076077238836622982900945173E1L, 1569 1.0 1570 ]; 1571 1572 enum T OF = 1.1356523406294143949492E4L; 1573 enum T UF = -4.5054566736396445112120088E1L; 1574 } 1575 else static if (realFormat == RealFormat.ieeeDouble) 1576 { 1577 static immutable T[3] P = [ 1578 9.9999999999999999991025E-1, 1579 3.0299440770744196129956E-2, 1580 1.2617719307481059087798E-4, 1581 ]; 1582 static immutable T[4] Q = [ 1583 2.0000000000000000000897E0, 1584 2.2726554820815502876593E-1, 1585 2.5244834034968410419224E-3, 1586 3.0019850513866445504159E-6, 1587 ]; 1588 } 1589 else 1590 static assert(0, "no coefficients for expm1()"); 1591 1592 static if (realFormat == RealFormat.ieeeDouble) // special case for double precision 1593 { 1594 if (x < -0.5 || x > 0.5) 1595 return exp(x) - 1.0; 1596 if (x == 0.0) 1597 return x; 1598 1599 const T xx = x * x; 1600 x = x * poly(xx, P); 1601 x = x / (poly(xx, Q) - x); 1602 return x + x; 1603 } 1604 else 1605 { 1606 // C1 + C2 = LN2. 1607 enum T C1 = 6.9314575195312500000000E-1L; 1608 enum T C2 = 1.428606820309417232121458176568075500134E-6L; 1609 1610 // Special cases. 1611 if (x > OF) 1612 return real.infinity; 1613 if (x == cast(T) 0.0) 1614 return x; 1615 if (x < UF) 1616 return -1.0; 1617 1618 // Express x = LN2 (n + remainder), remainder not exceeding 1/2. 1619 int n = cast(int) floor((cast(T) 0.5) + x / cast(T) LN2); 1620 x -= n * C1; 1621 x -= n * C2; 1622 1623 // Rational approximation: 1624 // exp(x) - 1 = x + 0.5 x^^2 + x^^3 P(x) / Q(x) 1625 T px = x * poly(x, P); 1626 T qx = poly(x, Q); 1627 const T xx = x * x; 1628 qx = x + ((cast(T) 0.5) * xx + xx * px / qx); 1629 1630 // We have qx = exp(remainder LN2) - 1, so: 1631 // exp(x) - 1 = 2^^n (qx + 1) - 1 = 2^^n qx + 2^^n - 1. 1632 px = core.math.ldexp(cast(T) 1.0, n); 1633 x = px * qx + (px - cast(T) 1.0); 1634 1635 return x; 1636 } 1637 } 1638 1639 @safe @nogc nothrow unittest 1640 { 1641 import std.math.traits : isNaN; 1642 import std.math.operations : isClose, CommonDefaultFor; 1643 1644 static void testExpm1(T)() 1645 { 1646 // NaN 1647 assert(isNaN(expm1(cast(T) T.nan))); 1648 1649 static immutable T[] xs = [ -2, -0.75, -0.3, 0.0, 0.1, 0.2, 0.5, 1.0 ]; 1650 foreach (x; xs) 1651 { 1652 const T e = expm1(x); 1653 const T r = exp(x) - 1; 1654 1655 //printf("expm1(%Lg) = %Lg, should approximately be %Lg\n", cast(real) x, cast(real) e, cast(real) r); 1656 assert(isClose(r, e, CommonDefaultFor!(T,T), CommonDefaultFor!(T,T))); 1657 } 1658 } 1659 1660 import std.meta : AliasSeq; 1661 foreach (T; AliasSeq!(real, double)) 1662 testExpm1!T(); 1663 } 1664 1665 /** 1666 * Calculates 2$(SUPERSCRIPT x). 1667 * 1668 * $(TABLE_SV 1669 * $(TR $(TH x) $(TH exp2(x)) ) 1670 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) 1671 * $(TR $(TD -$(INFIN)) $(TD +0.0) ) 1672 * $(TR $(TD $(NAN)) $(TD $(NAN)) ) 1673 * ) 1674 */ 1675 pragma(inline, true) 1676 real exp2(real x) @nogc @trusted pure nothrow // TODO: @safe 1677 { 1678 version (InlineAsm_X87) 1679 { 1680 if (!__ctfe) 1681 return exp2Asm(x); 1682 } 1683 return exp2Impl(x); 1684 } 1685 1686 /// ditto 1687 pragma(inline, true) 1688 double exp2(double x) @nogc @safe pure nothrow { return __ctfe ? cast(double) exp2(cast(real) x) : exp2Impl(x); } 1689 1690 /// ditto 1691 pragma(inline, true) 1692 float exp2(float x) @nogc @safe pure nothrow { return __ctfe ? cast(float) exp2(cast(real) x) : exp2Impl(x); } 1693 1694 /// 1695 @safe unittest 1696 { 1697 import std.math.traits : isIdentical; 1698 import std.math.operations : feqrel; 1699 1700 assert(isIdentical(exp2(0.0), 1.0)); 1701 assert(exp2(2.0).feqrel(4.0) > 16); 1702 assert(exp2(8.0).feqrel(256.0) > 16); 1703 } 1704 1705 @safe unittest 1706 { 1707 version (CRuntime_Microsoft) {} else // aexp2/exp2f/exp2l not implemented 1708 { 1709 assert( core.stdc.math.exp2f(0.0f) == 1 ); 1710 assert( core.stdc.math.exp2 (0.0) == 1 ); 1711 assert( core.stdc.math.exp2l(0.0L) == 1 ); 1712 } 1713 } 1714 1715 version (InlineAsm_X87) 1716 private real exp2Asm(real x) @nogc @trusted pure nothrow 1717 { 1718 version (X86) 1719 { 1720 enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 1721 1722 asm pure nothrow @nogc 1723 { 1724 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant. 1725 * Author: Don Clugston. 1726 * 1727 * exp2(x) = 2^^(rndint(x))* 2^^(y-rndint(x)) 1728 * The trick for high performance is to avoid the fscale(28cycles on core2), 1729 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction. 1730 * 1731 * We can do frndint by using fist. BUT we can't use it for huge numbers, 1732 * because it will set the Invalid Operation flag if overflow or NaN occurs. 1733 * Fortunately, whenever this happens the result would be zero or infinity. 1734 * 1735 * We can perform fscale by directly poking into the exponent. BUT this doesn't 1736 * work for the (very rare) cases where the result is subnormal. So we fall back 1737 * to the slow method in that case. 1738 */ 1739 naked; 1740 fld real ptr [ESP+4] ; // x 1741 mov AX, [ESP+4+8]; // AX = exponent and sign 1742 sub ESP, 12+8; // Create scratch space on the stack 1743 // [ESP,ESP+2] = scratchint 1744 // [ESP+4..+6, +8..+10, +10] = scratchreal 1745 // set scratchreal mantissa = 1.0 1746 mov dword ptr [ESP+8], 0; 1747 mov dword ptr [ESP+8+4], 0x80000000; 1748 and AX, 0x7FFF; // drop sign bit 1749 cmp AX, 0x401D; // avoid InvalidException in fist 1750 jae L_extreme; 1751 fist dword ptr [ESP]; // scratchint = rndint(x) 1752 fisub dword ptr [ESP]; // x - rndint(x) 1753 // and now set scratchreal exponent 1754 mov EAX, [ESP]; 1755 add EAX, 0x3fff; 1756 jle short L_subnormal; 1757 cmp EAX,0x8000; 1758 jge short L_overflow; 1759 mov [ESP+8+8],AX; 1760 L_normal: 1761 f2xm1; 1762 fld1; 1763 faddp ST(1), ST; // 2^^(x-rndint(x)) 1764 fld real ptr [ESP+8] ; // 2^^rndint(x) 1765 add ESP,12+8; 1766 fmulp ST(1), ST; 1767 ret PARAMSIZE; 1768 1769 L_subnormal: 1770 // Result will be subnormal. 1771 // In this rare case, the simple poking method doesn't work. 1772 // The speed doesn't matter, so use the slow fscale method. 1773 fild dword ptr [ESP]; // scratchint 1774 fld1; 1775 fscale; 1776 fstp real ptr [ESP+8]; // scratchreal = 2^^scratchint 1777 fstp ST(0); // drop scratchint 1778 jmp L_normal; 1779 1780 L_extreme: // Extreme exponent. X is very large positive, very 1781 // large negative, infinity, or NaN. 1782 fxam; 1783 fstsw AX; 1784 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1785 jz L_was_nan; // if x is NaN, returns x 1786 // set scratchreal = real.min_normal 1787 // squaring it will return 0, setting underflow flag 1788 mov word ptr [ESP+8+8], 1; 1789 test AX, 0x0200; 1790 jnz L_waslargenegative; 1791 L_overflow: 1792 // Set scratchreal = real.max. 1793 // squaring it will create infinity, and set overflow flag. 1794 mov word ptr [ESP+8+8], 0x7FFE; 1795 L_waslargenegative: 1796 fstp ST(0); 1797 fld real ptr [ESP+8]; // load scratchreal 1798 fmul ST(0), ST; // square it, to create havoc! 1799 L_was_nan: 1800 add ESP,12+8; 1801 ret PARAMSIZE; 1802 } 1803 } 1804 else version (X86_64) 1805 { 1806 asm pure nothrow @nogc 1807 { 1808 naked; 1809 } 1810 version (Win64) 1811 { 1812 asm pure nothrow @nogc 1813 { 1814 fld real ptr [RCX]; // x 1815 mov AX,[RCX+8]; // AX = exponent and sign 1816 } 1817 } 1818 else 1819 { 1820 asm pure nothrow @nogc 1821 { 1822 fld real ptr [RSP+8]; // x 1823 mov AX,[RSP+8+8]; // AX = exponent and sign 1824 } 1825 } 1826 asm pure nothrow @nogc 1827 { 1828 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant. 1829 * Author: Don Clugston. 1830 * 1831 * exp2(x) = 2^(rndint(x))* 2^(y-rndint(x)) 1832 * The trick for high performance is to avoid the fscale(28cycles on core2), 1833 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction. 1834 * 1835 * We can do frndint by using fist. BUT we can't use it for huge numbers, 1836 * because it will set the Invalid Operation flag is overflow or NaN occurs. 1837 * Fortunately, whenever this happens the result would be zero or infinity. 1838 * 1839 * We can perform fscale by directly poking into the exponent. BUT this doesn't 1840 * work for the (very rare) cases where the result is subnormal. So we fall back 1841 * to the slow method in that case. 1842 */ 1843 sub RSP, 24; // Create scratch space on the stack 1844 // [RSP,RSP+2] = scratchint 1845 // [RSP+4..+6, +8..+10, +10] = scratchreal 1846 // set scratchreal mantissa = 1.0 1847 mov dword ptr [RSP+8], 0; 1848 mov dword ptr [RSP+8+4], 0x80000000; 1849 and AX, 0x7FFF; // drop sign bit 1850 cmp AX, 0x401D; // avoid InvalidException in fist 1851 jae L_extreme; 1852 fist dword ptr [RSP]; // scratchint = rndint(x) 1853 fisub dword ptr [RSP]; // x - rndint(x) 1854 // and now set scratchreal exponent 1855 mov EAX, [RSP]; 1856 add EAX, 0x3fff; 1857 jle short L_subnormal; 1858 cmp EAX,0x8000; 1859 jge short L_overflow; 1860 mov [RSP+8+8],AX; 1861 L_normal: 1862 f2xm1; 1863 fld1; 1864 fadd; // 2^(x-rndint(x)) 1865 fld real ptr [RSP+8] ; // 2^rndint(x) 1866 add RSP,24; 1867 fmulp ST(1), ST; 1868 ret; 1869 1870 L_subnormal: 1871 // Result will be subnormal. 1872 // In this rare case, the simple poking method doesn't work. 1873 // The speed doesn't matter, so use the slow fscale method. 1874 fild dword ptr [RSP]; // scratchint 1875 fld1; 1876 fscale; 1877 fstp real ptr [RSP+8]; // scratchreal = 2^scratchint 1878 fstp ST(0); // drop scratchint 1879 jmp L_normal; 1880 1881 L_extreme: // Extreme exponent. X is very large positive, very 1882 // large negative, infinity, or NaN. 1883 fxam; 1884 fstsw AX; 1885 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1886 jz L_was_nan; // if x is NaN, returns x 1887 // set scratchreal = real.min 1888 // squaring it will return 0, setting underflow flag 1889 mov word ptr [RSP+8+8], 1; 1890 test AX, 0x0200; 1891 jnz L_waslargenegative; 1892 L_overflow: 1893 // Set scratchreal = real.max. 1894 // squaring it will create infinity, and set overflow flag. 1895 mov word ptr [RSP+8+8], 0x7FFE; 1896 L_waslargenegative: 1897 fstp ST(0); 1898 fld real ptr [RSP+8]; // load scratchreal 1899 fmul ST(0), ST; // square it, to create havoc! 1900 L_was_nan: 1901 add RSP,24; 1902 ret; 1903 } 1904 } 1905 else 1906 static assert(0); 1907 } 1908 1909 private T exp2Impl(T)(T x) @nogc @safe pure nothrow 1910 { 1911 import std.math : floatTraits, RealFormat; 1912 import std.math.traits : isNaN; 1913 import std.math.rounding : floor; 1914 import std.math.algebraic : poly; 1915 1916 // Coefficients for exp2(x) 1917 enum realFormat = floatTraits!T.realFormat; 1918 static if (realFormat == RealFormat.ieeeQuadruple) 1919 { 1920 static immutable T[5] P = [ 1921 9.079594442980146270952372234833529694788E12L, 1922 1.530625323728429161131811299626419117557E11L, 1923 5.677513871931844661829755443994214173883E8L, 1924 6.185032670011643762127954396427045467506E5L, 1925 1.587171580015525194694938306936721666031E2L 1926 ]; 1927 1928 static immutable T[6] Q = [ 1929 2.619817175234089411411070339065679229869E13L, 1930 1.490560994263653042761789432690793026977E12L, 1931 1.092141473886177435056423606755843616331E10L, 1932 2.186249607051644894762167991800811827835E7L, 1933 1.236602014442099053716561665053645270207E4L, 1934 1.0 1935 ]; 1936 } 1937 else static if (realFormat == RealFormat.ieeeExtended) 1938 { 1939 static immutable T[3] P = [ 1940 2.0803843631901852422887E6L, 1941 3.0286971917562792508623E4L, 1942 6.0614853552242266094567E1L, 1943 ]; 1944 static immutable T[4] Q = [ 1945 6.0027204078348487957118E6L, 1946 3.2772515434906797273099E5L, 1947 1.7492876999891839021063E3L, 1948 1.0000000000000000000000E0L, 1949 ]; 1950 } 1951 else static if (realFormat == RealFormat.ieeeDouble) 1952 { 1953 static immutable T[3] P = [ 1954 1.51390680115615096133E3L, 1955 2.02020656693165307700E1L, 1956 2.30933477057345225087E-2L, 1957 ]; 1958 static immutable T[3] Q = [ 1959 4.36821166879210612817E3L, 1960 2.33184211722314911771E2L, 1961 1.00000000000000000000E0L, 1962 ]; 1963 } 1964 else static if (realFormat == RealFormat.ieeeSingle) 1965 { 1966 static immutable T[6] P = [ 1967 6.931472028550421E-001L, 1968 2.402264791363012E-001L, 1969 5.550332471162809E-002L, 1970 9.618437357674640E-003L, 1971 1.339887440266574E-003L, 1972 1.535336188319500E-004L, 1973 ]; 1974 } 1975 else 1976 static assert(0, "no coefficients for exp2()"); 1977 1978 // Overflow and Underflow limits. 1979 enum T OF = T.max_exp; 1980 enum T UF = T.min_exp - 1; 1981 1982 // Special cases. 1983 if (isNaN(x)) 1984 return x; 1985 if (x > OF) 1986 return real.infinity; 1987 if (x < UF) 1988 return 0.0; 1989 1990 static if (realFormat == RealFormat.ieeeSingle) // special case for single precision 1991 { 1992 // The following is necessary because range reduction blows up. 1993 if (x == 0.0f) 1994 return 1.0f; 1995 1996 // Separate into integer and fractional parts. 1997 const T i = floor(x); 1998 int n = cast(int) i; 1999 x -= i; 2000 if (x > 0.5f) 2001 { 2002 n += 1; 2003 x -= 1.0f; 2004 } 2005 2006 // Rational approximation: 2007 // exp2(x) = 1.0 + x P(x) 2008 x = 1.0f + x * poly(x, P); 2009 } 2010 else 2011 { 2012 // Separate into integer and fractional parts. 2013 const T i = floor(x + cast(T) 0.5); 2014 int n = cast(int) i; 2015 x -= i; 2016 2017 // Rational approximation: 2018 // exp2(x) = 1.0 + 2x P(x^^2) / (Q(x^^2) - P(x^^2)) 2019 const T xx = x * x; 2020 const T px = x * poly(xx, P); 2021 x = px / (poly(xx, Q) - px); 2022 x = (cast(T) 1.0) + (cast(T) 2.0) * x; 2023 } 2024 2025 // Scale by power of 2. 2026 x = core.math.ldexp(x, n); 2027 2028 return x; 2029 } 2030 2031 @safe @nogc nothrow unittest 2032 { 2033 import std.math.operations : feqrel, NaN, isClose; 2034 import std.math.traits : isIdentical; 2035 import std.math.constants : SQRT2; 2036 2037 assert(feqrel(exp2(0.5L), SQRT2) >= real.mant_dig -1); 2038 assert(exp2(8.0L) == 256.0); 2039 assert(exp2(-9.0L)== 1.0L/512.0); 2040 2041 static void testExp2(T)() 2042 { 2043 // NaN 2044 const T specialNaN = NaN(0x0123L); 2045 assert(isIdentical(exp2(specialNaN), specialNaN)); 2046 2047 // over-/underflow 2048 enum T OF = T.max_exp; 2049 enum T UF = T.min_exp - T.mant_dig; 2050 assert(isIdentical(exp2(OF + 1), cast(T) T.infinity)); 2051 assert(isIdentical(exp2(UF - 1), cast(T) 0.0)); 2052 2053 static immutable T[2][] vals = 2054 [ 2055 // x, exp2(x) 2056 [ 0.0, 1.0 ], 2057 [ -0.0, 1.0 ], 2058 [ 0.5, SQRT2 ], 2059 [ 8.0, 256.0 ], 2060 [ -9.0, 1.0 / 512 ], 2061 ]; 2062 2063 foreach (ref val; vals) 2064 { 2065 const T x = val[0]; 2066 const T r = val[1]; 2067 const T e = exp2(x); 2068 2069 //printf("exp2(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) e, cast(real) r); 2070 assert(isClose(r, e)); 2071 } 2072 } 2073 2074 import std.meta : AliasSeq; 2075 foreach (T; AliasSeq!(real, double, float)) 2076 testExp2!T(); 2077 } 2078 2079 /********************************************************************* 2080 * Separate floating point value into significand and exponent. 2081 * 2082 * Returns: 2083 * Calculate and return $(I x) and $(I exp) such that 2084 * value =$(I x)*2$(SUPERSCRIPT exp) and 2085 * .5 $(LT)= |$(I x)| $(LT) 1.0 2086 * 2087 * $(I x) has same sign as value. 2088 * 2089 * $(TABLE_SV 2090 * $(TR $(TH value) $(TH returns) $(TH exp)) 2091 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD 0)) 2092 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD int.max)) 2093 * $(TR $(TD -$(INFIN)) $(TD -$(INFIN)) $(TD int.min)) 2094 * $(TR $(TD $(PLUSMN)$(NAN)) $(TD $(PLUSMN)$(NAN)) $(TD int.min)) 2095 * ) 2096 */ 2097 T frexp(T)(const T value, out int exp) @trusted pure nothrow @nogc 2098 if (isFloatingPoint!T) 2099 { 2100 import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; 2101 import std.math.traits : isSubnormal; 2102 2103 if (__ctfe) 2104 { 2105 // Handle special cases. 2106 if (value == 0) { exp = 0; return value; } 2107 if (value == T.infinity) { exp = int.max; return value; } 2108 if (value == -T.infinity || value != value) { exp = int.min; return value; } 2109 // Handle ordinary cases. 2110 // In CTFE there is no performance advantage for having separate 2111 // paths for different floating point types. 2112 T absValue = value < 0 ? -value : value; 2113 int expCount; 2114 static if (T.mant_dig > double.mant_dig) 2115 { 2116 for (; absValue >= 0x1.0p+1024L; absValue *= 0x1.0p-1024L) 2117 expCount += 1024; 2118 for (; absValue < 0x1.0p-1021L; absValue *= 0x1.0p+1021L) 2119 expCount -= 1021; 2120 } 2121 const double dval = cast(double) absValue; 2122 int dexp = cast(int) (((*cast(const long*) &dval) >>> 52) & 0x7FF) + double.min_exp - 2; 2123 dexp++; 2124 expCount += dexp; 2125 absValue *= 2.0 ^^ -dexp; 2126 // If the original value was subnormal or if it was a real 2127 // then absValue can still be outside the [0.5, 1.0) range. 2128 if (absValue < 0.5) 2129 { 2130 assert(T.mant_dig > double.mant_dig || isSubnormal(value)); 2131 do 2132 { 2133 absValue += absValue; 2134 expCount--; 2135 } while (absValue < 0.5); 2136 } 2137 else 2138 { 2139 assert(absValue < 1 || T.mant_dig > double.mant_dig); 2140 for (; absValue >= 1; absValue *= T(0.5)) 2141 expCount++; 2142 } 2143 exp = expCount; 2144 return value < 0 ? -absValue : absValue; 2145 } 2146 2147 Unqual!T vf = value; 2148 ushort* vu = cast(ushort*)&vf; 2149 static if (is(immutable T == immutable float)) 2150 int* vi = cast(int*)&vf; 2151 else 2152 long* vl = cast(long*)&vf; 2153 int ex; 2154 alias F = floatTraits!T; 2155 2156 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2157 static if (F.realFormat == RealFormat.ieeeExtended || 2158 F.realFormat == RealFormat.ieeeExtended53) 2159 { 2160 if (ex) 2161 { // If exponent is non-zero 2162 if (ex == F.EXPMASK) // infinity or NaN 2163 { 2164 if (*vl & 0x7FFF_FFFF_FFFF_FFFF) // NaN 2165 { 2166 *vl |= 0xC000_0000_0000_0000; // convert NaNS to NaNQ 2167 exp = int.min; 2168 } 2169 else if (vu[F.EXPPOS_SHORT] & 0x8000) // negative infinity 2170 exp = int.min; 2171 else // positive infinity 2172 exp = int.max; 2173 2174 } 2175 else 2176 { 2177 exp = ex - F.EXPBIAS; 2178 vu[F.EXPPOS_SHORT] = (0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FFE; 2179 } 2180 } 2181 else if (!*vl) 2182 { 2183 // vf is +-0.0 2184 exp = 0; 2185 } 2186 else 2187 { 2188 // subnormal 2189 2190 vf *= F.RECIP_EPSILON; 2191 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2192 exp = ex - F.EXPBIAS - T.mant_dig + 1; 2193 vu[F.EXPPOS_SHORT] = ((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3FFE; 2194 } 2195 return vf; 2196 } 2197 else static if (F.realFormat == RealFormat.ieeeQuadruple) 2198 { 2199 if (ex) // If exponent is non-zero 2200 { 2201 if (ex == F.EXPMASK) 2202 { 2203 // infinity or NaN 2204 if (vl[MANTISSA_LSB] | 2205 (vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) // NaN 2206 { 2207 // convert NaNS to NaNQ 2208 vl[MANTISSA_MSB] |= 0x0000_8000_0000_0000; 2209 exp = int.min; 2210 } 2211 else if (vu[F.EXPPOS_SHORT] & 0x8000) // negative infinity 2212 exp = int.min; 2213 else // positive infinity 2214 exp = int.max; 2215 } 2216 else 2217 { 2218 exp = ex - F.EXPBIAS; 2219 vu[F.EXPPOS_SHORT] = F.EXPBIAS | (0x8000 & vu[F.EXPPOS_SHORT]); 2220 } 2221 } 2222 else if ((vl[MANTISSA_LSB] | 2223 (vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0) 2224 { 2225 // vf is +-0.0 2226 exp = 0; 2227 } 2228 else 2229 { 2230 // subnormal 2231 vf *= F.RECIP_EPSILON; 2232 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2233 exp = ex - F.EXPBIAS - T.mant_dig + 1; 2234 vu[F.EXPPOS_SHORT] = F.EXPBIAS | (0x8000 & vu[F.EXPPOS_SHORT]); 2235 } 2236 return vf; 2237 } 2238 else static if (F.realFormat == RealFormat.ieeeDouble) 2239 { 2240 if (ex) // If exponent is non-zero 2241 { 2242 if (ex == F.EXPMASK) // infinity or NaN 2243 { 2244 if (*vl == 0x7FF0_0000_0000_0000) // positive infinity 2245 { 2246 exp = int.max; 2247 } 2248 else if (*vl == 0xFFF0_0000_0000_0000) // negative infinity 2249 exp = int.min; 2250 else 2251 { // NaN 2252 *vl |= 0x0008_0000_0000_0000; // convert NaNS to NaNQ 2253 exp = int.min; 2254 } 2255 } 2256 else 2257 { 2258 exp = (ex - F.EXPBIAS) >> 4; 2259 vu[F.EXPPOS_SHORT] = cast(ushort)((0x800F & vu[F.EXPPOS_SHORT]) | 0x3FE0); 2260 } 2261 } 2262 else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF)) 2263 { 2264 // vf is +-0.0 2265 exp = 0; 2266 } 2267 else 2268 { 2269 // subnormal 2270 vf *= F.RECIP_EPSILON; 2271 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2272 exp = ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1; 2273 vu[F.EXPPOS_SHORT] = 2274 cast(ushort)(((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3FE0); 2275 } 2276 return vf; 2277 } 2278 else static if (F.realFormat == RealFormat.ieeeSingle) 2279 { 2280 if (ex) // If exponent is non-zero 2281 { 2282 if (ex == F.EXPMASK) // infinity or NaN 2283 { 2284 if (*vi == 0x7F80_0000) // positive infinity 2285 { 2286 exp = int.max; 2287 } 2288 else if (*vi == 0xFF80_0000) // negative infinity 2289 exp = int.min; 2290 else 2291 { // NaN 2292 *vi |= 0x0040_0000; // convert NaNS to NaNQ 2293 exp = int.min; 2294 } 2295 } 2296 else 2297 { 2298 exp = (ex - F.EXPBIAS) >> 7; 2299 vu[F.EXPPOS_SHORT] = cast(ushort)((0x807F & vu[F.EXPPOS_SHORT]) | 0x3F00); 2300 } 2301 } 2302 else if (!(*vi & 0x7FFF_FFFF)) 2303 { 2304 // vf is +-0.0 2305 exp = 0; 2306 } 2307 else 2308 { 2309 // subnormal 2310 vf *= F.RECIP_EPSILON; 2311 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2312 exp = ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1; 2313 vu[F.EXPPOS_SHORT] = 2314 cast(ushort)(((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3F00); 2315 } 2316 return vf; 2317 } 2318 else // static if (F.realFormat == RealFormat.ibmExtended) 2319 { 2320 assert(0, "frexp not implemented"); 2321 } 2322 } 2323 2324 /// 2325 @safe unittest 2326 { 2327 import std.math.operations : isClose; 2328 2329 int exp; 2330 real mantissa = frexp(123.456L, exp); 2331 2332 assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L)); 2333 2334 assert(frexp(-real.nan, exp) && exp == int.min); 2335 assert(frexp(real.nan, exp) && exp == int.min); 2336 assert(frexp(-real.infinity, exp) == -real.infinity && exp == int.min); 2337 assert(frexp(real.infinity, exp) == real.infinity && exp == int.max); 2338 assert(frexp(-0.0, exp) == -0.0 && exp == 0); 2339 assert(frexp(0.0, exp) == 0.0 && exp == 0); 2340 } 2341 2342 @safe @nogc nothrow unittest 2343 { 2344 import std.math.operations : isClose; 2345 2346 int exp; 2347 real mantissa = frexp(123.456L, exp); 2348 2349 // check if values are equal to 19 decimal digits of precision 2350 assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L, 1e-18)); 2351 } 2352 2353 @safe unittest 2354 { 2355 import std.math : floatTraits, RealFormat; 2356 import std.math.traits : isIdentical; 2357 import std.meta : AliasSeq; 2358 import std.typecons : tuple, Tuple; 2359 2360 static foreach (T; AliasSeq!(real, double, float)) 2361 {{ 2362 Tuple!(T, T, int)[] vals = [ // x,frexp,exp 2363 tuple(T(0.0), T( 0.0 ), 0), 2364 tuple(T(-0.0), T( -0.0), 0), 2365 tuple(T(1.0), T( .5 ), 1), 2366 tuple(T(-1.0), T( -.5 ), 1), 2367 tuple(T(2.0), T( .5 ), 2), 2368 tuple(T(float.min_normal/2.0f), T(.5), -126), 2369 tuple(T.infinity, T.infinity, int.max), 2370 tuple(-T.infinity, -T.infinity, int.min), 2371 tuple(T.nan, T.nan, int.min), 2372 tuple(-T.nan, -T.nan, int.min), 2373 2374 // https://issues.dlang.org/show_bug.cgi?id=16026: 2375 tuple(3 * (T.min_normal * T.epsilon), T( .75), (T.min_exp - T.mant_dig) + 2) 2376 ]; 2377 2378 foreach (elem; vals) 2379 { 2380 T x = elem[0]; 2381 T e = elem[1]; 2382 int exp = elem[2]; 2383 int eptr; 2384 T v = frexp(x, eptr); 2385 assert(isIdentical(e, v)); 2386 assert(exp == eptr); 2387 } 2388 2389 static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended) 2390 { 2391 static T[3][] extendedvals = [ // x,frexp,exp 2392 [0x1.a5f1c2eb3fe4efp+73L, 0x1.A5F1C2EB3FE4EFp-1L, 74], // normal 2393 [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063], 2394 [T.min_normal, .5, -16381], 2395 [T.min_normal/2.0L, .5, -16382] // subnormal 2396 ]; 2397 foreach (elem; extendedvals) 2398 { 2399 T x = elem[0]; 2400 T e = elem[1]; 2401 int exp = cast(int) elem[2]; 2402 int eptr; 2403 T v = frexp(x, eptr); 2404 assert(isIdentical(e, v)); 2405 assert(exp == eptr); 2406 } 2407 } 2408 }} 2409 2410 // CTFE 2411 alias CtfeFrexpResult= Tuple!(real, int); 2412 static CtfeFrexpResult ctfeFrexp(T)(const T value) 2413 { 2414 int exp; 2415 auto significand = frexp(value, exp); 2416 return CtfeFrexpResult(significand, exp); 2417 } 2418 static foreach (T; AliasSeq!(real, double, float)) 2419 {{ 2420 enum Tuple!(T, T, int)[] vals = [ // x,frexp,exp 2421 tuple(T(0.0), T( 0.0 ), 0), 2422 tuple(T(-0.0), T( -0.0), 0), 2423 tuple(T(1.0), T( .5 ), 1), 2424 tuple(T(-1.0), T( -.5 ), 1), 2425 tuple(T(2.0), T( .5 ), 2), 2426 tuple(T(float.min_normal/2.0f), T(.5), -126), 2427 tuple(T.infinity, T.infinity, int.max), 2428 tuple(-T.infinity, -T.infinity, int.min), 2429 tuple(T.nan, T.nan, int.min), 2430 tuple(-T.nan, -T.nan, int.min), 2431 2432 // https://issues.dlang.org/show_bug.cgi?id=16026: 2433 tuple(3 * (T.min_normal * T.epsilon), T( .75), (T.min_exp - T.mant_dig) + 2) 2434 ]; 2435 2436 static foreach (elem; vals) 2437 { 2438 static assert(ctfeFrexp(elem[0]) is CtfeFrexpResult(elem[1], elem[2])); 2439 } 2440 2441 static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended) 2442 { 2443 enum T[3][] extendedvals = [ // x,frexp,exp 2444 [0x1.a5f1c2eb3fe4efp+73L, 0x1.A5F1C2EB3FE4EFp-1L, 74], // normal 2445 [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063], 2446 [T.min_normal, .5, -16381], 2447 [T.min_normal/2.0L, .5, -16382] // subnormal 2448 ]; 2449 static foreach (elem; extendedvals) 2450 { 2451 static assert(ctfeFrexp(elem[0]) is CtfeFrexpResult(elem[1], cast(int) elem[2])); 2452 } 2453 } 2454 }} 2455 } 2456 2457 @safe unittest 2458 { 2459 import std.meta : AliasSeq; 2460 void foo() { 2461 static foreach (T; AliasSeq!(real, double, float)) 2462 {{ 2463 int exp; 2464 const T a = 1; 2465 immutable T b = 2; 2466 auto c = frexp(a, exp); 2467 auto d = frexp(b, exp); 2468 }} 2469 } 2470 } 2471 2472 /****************************************** 2473 * Extracts the exponent of x as a signed integral value. 2474 * 2475 * If x is not a special value, the result is the same as 2476 * $(D cast(int) logb(x)). 2477 * 2478 * $(TABLE_SV 2479 * $(TR $(TH x) $(TH ilogb(x)) $(TH Range error?)) 2480 * $(TR $(TD 0) $(TD FP_ILOGB0) $(TD yes)) 2481 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD int.max) $(TD no)) 2482 * $(TR $(TD $(NAN)) $(TD FP_ILOGBNAN) $(TD no)) 2483 * ) 2484 */ 2485 int ilogb(T)(const T x) @trusted pure nothrow @nogc 2486 if (isFloatingPoint!T) 2487 { 2488 import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; 2489 2490 import core.bitop : bsr; 2491 alias F = floatTraits!T; 2492 2493 union floatBits 2494 { 2495 T rv; 2496 ushort[T.sizeof/2] vu; 2497 uint[T.sizeof/4] vui; 2498 static if (T.sizeof >= 8) 2499 ulong[T.sizeof/8] vul; 2500 } 2501 floatBits y = void; 2502 y.rv = x; 2503 2504 int ex = y.vu[F.EXPPOS_SHORT] & F.EXPMASK; 2505 static if (F.realFormat == RealFormat.ieeeExtended || 2506 F.realFormat == RealFormat.ieeeExtended53) 2507 { 2508 if (ex) 2509 { 2510 // If exponent is non-zero 2511 if (ex == F.EXPMASK) // infinity or NaN 2512 { 2513 if (y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF) // NaN 2514 return FP_ILOGBNAN; 2515 else // +-infinity 2516 return int.max; 2517 } 2518 else 2519 { 2520 return ex - F.EXPBIAS - 1; 2521 } 2522 } 2523 else if (!y.vul[0]) 2524 { 2525 // vf is +-0.0 2526 return FP_ILOGB0; 2527 } 2528 else 2529 { 2530 // subnormal 2531 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(y.vul[0]); 2532 } 2533 } 2534 else static if (F.realFormat == RealFormat.ieeeQuadruple) 2535 { 2536 if (ex) // If exponent is non-zero 2537 { 2538 if (ex == F.EXPMASK) 2539 { 2540 // infinity or NaN 2541 if (y.vul[MANTISSA_LSB] | ( y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) // NaN 2542 return FP_ILOGBNAN; 2543 else // +- infinity 2544 return int.max; 2545 } 2546 else 2547 { 2548 return ex - F.EXPBIAS - 1; 2549 } 2550 } 2551 else if ((y.vul[MANTISSA_LSB] | (y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0) 2552 { 2553 // vf is +-0.0 2554 return FP_ILOGB0; 2555 } 2556 else 2557 { 2558 // subnormal 2559 const ulong msb = y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF; 2560 const ulong lsb = y.vul[MANTISSA_LSB]; 2561 if (msb) 2562 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(msb) + 64; 2563 else 2564 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(lsb); 2565 } 2566 } 2567 else static if (F.realFormat == RealFormat.ieeeDouble) 2568 { 2569 if (ex) // If exponent is non-zero 2570 { 2571 if (ex == F.EXPMASK) // infinity or NaN 2572 { 2573 if ((y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FF0_0000_0000_0000) // +- infinity 2574 return int.max; 2575 else // NaN 2576 return FP_ILOGBNAN; 2577 } 2578 else 2579 { 2580 return ((ex - F.EXPBIAS) >> 4) - 1; 2581 } 2582 } 2583 else if (!(y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF)) 2584 { 2585 // vf is +-0.0 2586 return FP_ILOGB0; 2587 } 2588 else 2589 { 2590 // subnormal 2591 enum MANTISSAMASK_64 = ((cast(ulong) F.MANTISSAMASK_INT) << 32) | 0xFFFF_FFFF; 2592 return ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1 + bsr(y.vul[0] & MANTISSAMASK_64); 2593 } 2594 } 2595 else static if (F.realFormat == RealFormat.ieeeSingle) 2596 { 2597 if (ex) // If exponent is non-zero 2598 { 2599 if (ex == F.EXPMASK) // infinity or NaN 2600 { 2601 if ((y.vui[0] & 0x7FFF_FFFF) == 0x7F80_0000) // +- infinity 2602 return int.max; 2603 else // NaN 2604 return FP_ILOGBNAN; 2605 } 2606 else 2607 { 2608 return ((ex - F.EXPBIAS) >> 7) - 1; 2609 } 2610 } 2611 else if (!(y.vui[0] & 0x7FFF_FFFF)) 2612 { 2613 // vf is +-0.0 2614 return FP_ILOGB0; 2615 } 2616 else 2617 { 2618 // subnormal 2619 const uint mantissa = y.vui[0] & F.MANTISSAMASK_INT; 2620 return ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1 + bsr(mantissa); 2621 } 2622 } 2623 else // static if (F.realFormat == RealFormat.ibmExtended) 2624 { 2625 assert(0, "ilogb not implemented"); 2626 } 2627 } 2628 /// ditto 2629 int ilogb(T)(const T x) @safe pure nothrow @nogc 2630 if (isIntegral!T && isUnsigned!T) 2631 { 2632 import core.bitop : bsr; 2633 if (x == 0) 2634 return FP_ILOGB0; 2635 else 2636 { 2637 static assert(T.sizeof <= ulong.sizeof, "integer size too large for the current ilogb implementation"); 2638 return bsr(x); 2639 } 2640 } 2641 /// ditto 2642 int ilogb(T)(const T x) @safe pure nothrow @nogc 2643 if (isIntegral!T && isSigned!T) 2644 { 2645 import std.traits : Unsigned; 2646 // Note: abs(x) can not be used because the return type is not Unsigned and 2647 // the return value would be wrong for x == int.min 2648 Unsigned!T absx = x >= 0 ? x : -x; 2649 return ilogb(absx); 2650 } 2651 2652 /// 2653 @safe pure unittest 2654 { 2655 assert(ilogb(1) == 0); 2656 assert(ilogb(3) == 1); 2657 assert(ilogb(3.0) == 1); 2658 assert(ilogb(100_000_000) == 26); 2659 2660 assert(ilogb(0) == FP_ILOGB0); 2661 assert(ilogb(0.0) == FP_ILOGB0); 2662 assert(ilogb(double.nan) == FP_ILOGBNAN); 2663 assert(ilogb(double.infinity) == int.max); 2664 } 2665 2666 /** 2667 Special return values of $(LREF ilogb). 2668 */ 2669 alias FP_ILOGB0 = core.stdc.math.FP_ILOGB0; 2670 /// ditto 2671 alias FP_ILOGBNAN = core.stdc.math.FP_ILOGBNAN; 2672 2673 /// 2674 @safe pure unittest 2675 { 2676 assert(ilogb(0) == FP_ILOGB0); 2677 assert(ilogb(0.0) == FP_ILOGB0); 2678 assert(ilogb(double.nan) == FP_ILOGBNAN); 2679 } 2680 2681 @safe nothrow @nogc unittest 2682 { 2683 import std.math : floatTraits, RealFormat; 2684 import std.math.operations : nextUp; 2685 import std.meta : AliasSeq; 2686 import std.typecons : Tuple; 2687 static foreach (F; AliasSeq!(float, double, real)) 2688 {{ 2689 alias T = Tuple!(F, int); 2690 T[13] vals = // x, ilogb(x) 2691 [ 2692 T( F.nan , FP_ILOGBNAN ), 2693 T( -F.nan , FP_ILOGBNAN ), 2694 T( F.infinity, int.max ), 2695 T( -F.infinity, int.max ), 2696 T( 0.0 , FP_ILOGB0 ), 2697 T( -0.0 , FP_ILOGB0 ), 2698 T( 2.0 , 1 ), 2699 T( 2.0001 , 1 ), 2700 T( 1.9999 , 0 ), 2701 T( 0.5 , -1 ), 2702 T( 123.123 , 6 ), 2703 T( -123.123 , 6 ), 2704 T( 0.123 , -4 ), 2705 ]; 2706 2707 foreach (elem; vals) 2708 { 2709 assert(ilogb(elem[0]) == elem[1]); 2710 } 2711 }} 2712 2713 // min_normal and subnormals 2714 assert(ilogb(-float.min_normal) == -126); 2715 assert(ilogb(nextUp(-float.min_normal)) == -127); 2716 assert(ilogb(nextUp(-float(0.0))) == -149); 2717 assert(ilogb(-double.min_normal) == -1022); 2718 assert(ilogb(nextUp(-double.min_normal)) == -1023); 2719 assert(ilogb(nextUp(-double(0.0))) == -1074); 2720 static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) 2721 { 2722 assert(ilogb(-real.min_normal) == -16382); 2723 assert(ilogb(nextUp(-real.min_normal)) == -16383); 2724 assert(ilogb(nextUp(-real(0.0))) == -16445); 2725 } 2726 else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) 2727 { 2728 assert(ilogb(-real.min_normal) == -1022); 2729 assert(ilogb(nextUp(-real.min_normal)) == -1023); 2730 assert(ilogb(nextUp(-real(0.0))) == -1074); 2731 } 2732 2733 // test integer types 2734 assert(ilogb(0) == FP_ILOGB0); 2735 assert(ilogb(int.max) == 30); 2736 assert(ilogb(int.min) == 31); 2737 assert(ilogb(uint.max) == 31); 2738 assert(ilogb(long.max) == 62); 2739 assert(ilogb(long.min) == 63); 2740 assert(ilogb(ulong.max) == 63); 2741 } 2742 2743 /******************************************* 2744 * Compute n * 2$(SUPERSCRIPT exp) 2745 * References: frexp 2746 */ 2747 2748 pragma(inline, true) 2749 real ldexp(real n, int exp) @safe pure nothrow @nogc { return core.math.ldexp(n, exp); } 2750 ///ditto 2751 pragma(inline, true) 2752 double ldexp(double n, int exp) @safe pure nothrow @nogc { return core.math.ldexp(n, exp); } 2753 ///ditto 2754 pragma(inline, true) 2755 float ldexp(float n, int exp) @safe pure nothrow @nogc { return core.math.ldexp(n, exp); } 2756 2757 /// 2758 @nogc @safe pure nothrow unittest 2759 { 2760 import std.meta : AliasSeq; 2761 static foreach (T; AliasSeq!(float, double, real)) 2762 {{ 2763 T r; 2764 2765 r = ldexp(3.0L, 3); 2766 assert(r == 24); 2767 2768 r = ldexp(cast(T) 3.0, cast(int) 3); 2769 assert(r == 24); 2770 2771 T n = 3.0; 2772 int exp = 3; 2773 r = ldexp(n, exp); 2774 assert(r == 24); 2775 }} 2776 } 2777 2778 @safe pure nothrow @nogc unittest 2779 { 2780 import std.math : floatTraits, RealFormat; 2781 2782 static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended || 2783 floatTraits!(real).realFormat == RealFormat.ieeeExtended53 || 2784 floatTraits!(real).realFormat == RealFormat.ieeeQuadruple) 2785 { 2786 assert(ldexp(1.0L, -16384) == 0x1p-16384L); 2787 assert(ldexp(1.0L, -16382) == 0x1p-16382L); 2788 int x; 2789 real n = frexp(0x1p-16384L, x); 2790 assert(n == 0.5L); 2791 assert(x==-16383); 2792 assert(ldexp(n, x)==0x1p-16384L); 2793 } 2794 else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) 2795 { 2796 assert(ldexp(1.0L, -1024) == 0x1p-1024L); 2797 assert(ldexp(1.0L, -1022) == 0x1p-1022L); 2798 int x; 2799 real n = frexp(0x1p-1024L, x); 2800 assert(n == 0.5L); 2801 assert(x==-1023); 2802 assert(ldexp(n, x)==0x1p-1024L); 2803 } 2804 else static assert(false, "Floating point type real not supported"); 2805 } 2806 2807 /* workaround https://issues.dlang.org/show_bug.cgi?id=14718 2808 float parsing depends on platform strtold 2809 @safe pure nothrow @nogc unittest 2810 { 2811 assert(ldexp(1.0, -1024) == 0x1p-1024); 2812 assert(ldexp(1.0, -1022) == 0x1p-1022); 2813 int x; 2814 double n = frexp(0x1p-1024, x); 2815 assert(n == 0.5); 2816 assert(x==-1023); 2817 assert(ldexp(n, x)==0x1p-1024); 2818 } 2819 2820 @safe pure nothrow @nogc unittest 2821 { 2822 assert(ldexp(1.0f, -128) == 0x1p-128f); 2823 assert(ldexp(1.0f, -126) == 0x1p-126f); 2824 int x; 2825 float n = frexp(0x1p-128f, x); 2826 assert(n == 0.5f); 2827 assert(x==-127); 2828 assert(ldexp(n, x)==0x1p-128f); 2829 } 2830 */ 2831 2832 @safe @nogc nothrow unittest 2833 { 2834 import std.math.operations : isClose; 2835 2836 static real[3][] vals = // value,exp,ldexp 2837 [ 2838 [ 0, 0, 0], 2839 [ 1, 0, 1], 2840 [ -1, 0, -1], 2841 [ 1, 1, 2], 2842 [ 123, 10, 125952], 2843 [ real.max, int.max, real.infinity], 2844 [ real.max, -int.max, 0], 2845 [ real.min_normal, -int.max, 0], 2846 ]; 2847 int i; 2848 2849 for (i = 0; i < vals.length; i++) 2850 { 2851 real x = vals[i][0]; 2852 int exp = cast(int) vals[i][1]; 2853 real z = vals[i][2]; 2854 real l = ldexp(x, exp); 2855 2856 assert(isClose(z, l, 1e-6)); 2857 } 2858 2859 real function(real, int) pldexp = &ldexp; 2860 assert(pldexp != null); 2861 } 2862 2863 private 2864 { 2865 // Coefficients shared across log(), log2(), log10(). 2866 template LogCoeffs(T) 2867 { 2868 import std.math : floatTraits, RealFormat; 2869 2870 static if (floatTraits!T.realFormat == RealFormat.ieeeQuadruple) 2871 { 2872 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 2873 // Theoretical peak relative error = 5.3e-37 2874 static immutable real[13] logP = [ 2875 1.313572404063446165910279910527789794488E4L, 2876 7.771154681358524243729929227226708890930E4L, 2877 2.014652742082537582487669938141683759923E5L, 2878 3.007007295140399532324943111654767187848E5L, 2879 2.854829159639697837788887080758954924001E5L, 2880 1.797628303815655343403735250238293741397E5L, 2881 7.594356839258970405033155585486712125861E4L, 2882 2.128857716871515081352991964243375186031E4L, 2883 3.824952356185897735160588078446136783779E3L, 2884 4.114517881637811823002128927449878962058E2L, 2885 2.321125933898420063925789532045674660756E1L, 2886 4.998469661968096229986658302195402690910E-1L, 2887 1.538612243596254322971797716843006400388E-6L 2888 ]; 2889 static immutable real[13] logQ = [ 2890 3.940717212190338497730839731583397586124E4L, 2891 2.626900195321832660448791748036714883242E5L, 2892 7.777690340007566932935753241556479363645E5L, 2893 1.347518538384329112529391120390701166528E6L, 2894 1.514882452993549494932585972882995548426E6L, 2895 1.158019977462989115839826904108208787040E6L, 2896 6.132189329546557743179177159925690841200E5L, 2897 2.248234257620569139969141618556349415120E5L, 2898 5.605842085972455027590989944010492125825E4L, 2899 9.147150349299596453976674231612674085381E3L, 2900 9.104928120962988414618126155557301584078E2L, 2901 4.839208193348159620282142911143429644326E1L, 2902 1.0 2903 ]; 2904 2905 // log2 uses the same coefficients as log. 2906 alias log2P = logP; 2907 alias log2Q = logQ; 2908 2909 // log10 uses the same coefficients as log. 2910 alias log10P = logP; 2911 alias log10Q = logQ; 2912 2913 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2) 2914 // where z = 2(x-1)/(x+1) 2915 // Theoretical peak relative error = 1.1e-35 2916 static immutable real[6] logR = [ 2917 1.418134209872192732479751274970992665513E5L, 2918 -8.977257995689735303686582344659576526998E4L, 2919 2.048819892795278657810231591630928516206E4L, 2920 -2.024301798136027039250415126250455056397E3L, 2921 8.057002716646055371965756206836056074715E1L, 2922 -8.828896441624934385266096344596648080902E-1L 2923 ]; 2924 static immutable real[7] logS = [ 2925 1.701761051846631278975701529965589676574E6L, 2926 -1.332535117259762928288745111081235577029E6L, 2927 4.001557694070773974936904547424676279307E5L, 2928 -5.748542087379434595104154610899551484314E4L, 2929 3.998526750980007367835804959888064681098E3L, 2930 -1.186359407982897997337150403816839480438E2L, 2931 1.0 2932 ]; 2933 } 2934 else static if (floatTraits!T.realFormat == RealFormat.ieeeExtended || 2935 floatTraits!T.realFormat == RealFormat.ieeeExtended53) 2936 { 2937 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 2938 // Theoretical peak relative error = 2.32e-20 2939 static immutable real[7] logP = [ 2940 2.0039553499201281259648E1L, 2941 5.7112963590585538103336E1L, 2942 6.0949667980987787057556E1L, 2943 2.9911919328553073277375E1L, 2944 6.5787325942061044846969E0L, 2945 4.9854102823193375972212E-1L, 2946 4.5270000862445199635215E-5L, 2947 ]; 2948 static immutable real[7] logQ = [ 2949 6.0118660497603843919306E1L, 2950 2.1642788614495947685003E2L, 2951 3.0909872225312059774938E2L, 2952 2.2176239823732856465394E2L, 2953 8.3047565967967209469434E1L, 2954 1.5062909083469192043167E1L, 2955 1.0000000000000000000000E0L, 2956 ]; 2957 2958 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 2959 // Theoretical peak relative error = 6.2e-22 2960 static immutable real[7] log2P = [ 2961 1.0747524399916215149070E2L, 2962 3.4258224542413922935104E2L, 2963 4.2401812743503691187826E2L, 2964 2.5620629828144409632571E2L, 2965 7.7671073698359539859595E1L, 2966 1.0767376367209449010438E1L, 2967 4.9962495940332550844739E-1L, 2968 ]; 2969 static immutable real[8] log2Q = [ 2970 3.2242573199748645407652E2L, 2971 1.2695660352705325274404E3L, 2972 2.0307734695595183428202E3L, 2973 1.6911722418503949084863E3L, 2974 7.7952888181207260646090E2L, 2975 1.9444210022760132894510E2L, 2976 2.3479774160285863271658E1L, 2977 1.0000000000000000000000E0, 2978 ]; 2979 2980 // log10 uses the same coefficients as log2. 2981 alias log10P = log2P; 2982 alias log10Q = log2Q; 2983 2984 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2) 2985 // where z = 2(x-1)/(x+1) 2986 // Theoretical peak relative error = 6.16e-22 2987 static immutable real[4] logR = [ 2988 -3.5717684488096787370998E1L, 2989 1.0777257190312272158094E1L, 2990 -7.1990767473014147232598E-1L, 2991 1.9757429581415468984296E-3L, 2992 ]; 2993 static immutable real[4] logS = [ 2994 -4.2861221385716144629696E2L, 2995 1.9361891836232102174846E2L, 2996 -2.6201045551331104417768E1L, 2997 1.0000000000000000000000E0L, 2998 ]; 2999 } 3000 else static if (floatTraits!T.realFormat == RealFormat.ieeeDouble) 3001 { 3002 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 3003 static immutable double[6] logP = [ 3004 7.70838733755885391666E0, 3005 1.79368678507819816313E1, 3006 1.44989225341610930846E1, 3007 4.70579119878881725854E0, 3008 4.97494994976747001425E-1, 3009 1.01875663804580931796E-4, 3010 ]; 3011 static immutable double[6] logQ = [ 3012 2.31251620126765340583E1, 3013 7.11544750618563894466E1, 3014 8.29875266912776603211E1, 3015 4.52279145837532221105E1, 3016 1.12873587189167450590E1, 3017 1.00000000000000000000E0, 3018 ]; 3019 3020 // log2 uses the same coefficients as log. 3021 alias log2P = logP; 3022 alias log2Q = logQ; 3023 3024 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 3025 static immutable double[7] log10P = [ 3026 4.58482948458143443514E-5, 3027 4.98531067254050724270E-1, 3028 6.56312093769992875930E0, 3029 2.97877425097986925891E1, 3030 6.06127134467767258030E1, 3031 5.67349287391754285487E1, 3032 1.98892446572874072159E1, 3033 ]; 3034 static immutable double[7] log10Q = [ 3035 1.00000000000000000000E0, 3036 1.50314182634250003249E1, 3037 8.27410449222435217021E1, 3038 2.20664384982121929218E2, 3039 3.07254189979530058263E2, 3040 2.14955586696422947765E2, 3041 5.96677339718622216300E1, 3042 ]; 3043 3044 // Coefficients for log(x) = z + z^^3 R(z)/S(z) 3045 // where z = 2(x-1)/(x+1) 3046 static immutable double[3] logR = [ 3047 -6.41409952958715622951E1, 3048 1.63866645699558079767E1, 3049 -7.89580278884799154124E-1, 3050 ]; 3051 static immutable double[4] logS = [ 3052 -7.69691943550460008604E2, 3053 3.12093766372244180303E2, 3054 -3.56722798256324312549E1, 3055 1.00000000000000000000E0, 3056 ]; 3057 } 3058 else static if (floatTraits!T.realFormat == RealFormat.ieeeSingle) 3059 { 3060 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x) 3061 static immutable float[9] logP = [ 3062 3.3333331174E-1, 3063 -2.4999993993E-1, 3064 2.0000714765E-1, 3065 -1.6668057665E-1, 3066 1.4249322787E-1, 3067 -1.2420140846E-1, 3068 1.1676998740E-1, 3069 -1.1514610310E-1, 3070 7.0376836292E-2, 3071 ]; 3072 3073 // log2 and log10 uses the same coefficients as log. 3074 alias log2P = logP; 3075 alias log10P = logP; 3076 } 3077 else 3078 static assert(0, "no coefficients for log()"); 3079 } 3080 } 3081 3082 /************************************** 3083 * Calculate the natural logarithm of x. 3084 * 3085 * $(TABLE_SV 3086 * $(TR $(TH x) $(TH log(x)) $(TH divide by 0?) $(TH invalid?)) 3087 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) 3088 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes)) 3089 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) 3090 * ) 3091 */ 3092 pragma(inline, true) 3093 real log(real x) @safe pure nothrow @nogc 3094 { 3095 version (INLINE_YL2X) 3096 { 3097 import std.math.constants : LN2; 3098 return core.math.yl2x(x, LN2); 3099 } 3100 else 3101 return logImpl(x); 3102 } 3103 3104 /// ditto 3105 pragma(inline, true) 3106 double log(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log(cast(real) x) : logImpl(x); } 3107 3108 /// ditto 3109 pragma(inline, true) 3110 float log(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log(cast(real) x) : logImpl(x); } 3111 3112 // @@@DEPRECATED_[2.112.0]@@@ 3113 deprecated("`std.math.exponential.log` called with argument types `(int)` matches both " 3114 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3115 real log(int x) @safe pure nothrow @nogc { return log(cast(real) x); } 3116 // @@@DEPRECATED_[2.112.0]@@@ 3117 deprecated("`std.math.exponential.log` called with argument types `(uint)` matches both " 3118 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3119 real log(uint x) @safe pure nothrow @nogc { return log(cast(real) x); } 3120 // @@@DEPRECATED_[2.112.0]@@@ 3121 deprecated("`std.math.exponential.log` called with argument types `(long)` matches both " 3122 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3123 real log(long x) @safe pure nothrow @nogc { return log(cast(real) x); } 3124 // @@@DEPRECATED_[2.112.0]@@@ 3125 deprecated("`std.math.exponential.log` called with argument types `(ulong)` matches both " 3126 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3127 real log(ulong x) @safe pure nothrow @nogc { return log(cast(real) x); } 3128 3129 /// 3130 @safe pure nothrow @nogc unittest 3131 { 3132 import std.math.operations : feqrel; 3133 import std.math.constants : E; 3134 3135 assert(feqrel(log(E), 1) >= real.mant_dig - 1); 3136 } 3137 3138 private T logImpl(T)(T x) @safe pure nothrow @nogc 3139 { 3140 import std.math.constants : SQRT1_2; 3141 import std.math.algebraic : poly; 3142 import std.math.traits : isInfinity, isNaN, signbit; 3143 import std.math : floatTraits, RealFormat; 3144 3145 alias coeffs = LogCoeffs!T; 3146 alias F = floatTraits!T; 3147 3148 static if (F.realFormat == RealFormat.ieeeExtended || 3149 F.realFormat == RealFormat.ieeeExtended53 || 3150 F.realFormat == RealFormat.ieeeQuadruple) 3151 { 3152 // C1 + C2 = LN2. 3153 enum T C1 = 6.93145751953125E-1L; 3154 enum T C2 = 1.428606820309417232121458176568075500134E-6L; 3155 } 3156 else static if (F.realFormat == RealFormat.ieeeDouble) 3157 { 3158 enum T C1 = 0.693359375; 3159 enum T C2 = -2.121944400546905827679e-4; 3160 } 3161 else static if (F.realFormat == RealFormat.ieeeSingle) 3162 { 3163 enum T C1 = 0.693359375; 3164 enum T C2 = -2.12194440e-4; 3165 } 3166 else 3167 static assert(0, "Not implemented for this architecture"); 3168 3169 // Special cases. 3170 if (isNaN(x)) 3171 return x; 3172 if (isInfinity(x) && !signbit(x)) 3173 return x; 3174 if (x == 0.0) 3175 return -T.infinity; 3176 if (x < 0.0) 3177 return T.nan; 3178 3179 // Separate mantissa from exponent. 3180 // Note, frexp is used so that denormal numbers will be handled properly. 3181 T y, z; 3182 int exp; 3183 3184 x = frexp(x, exp); 3185 3186 static if (F.realFormat == RealFormat.ieeeDouble || 3187 F.realFormat == RealFormat.ieeeExtended || 3188 F.realFormat == RealFormat.ieeeExtended53 || 3189 F.realFormat == RealFormat.ieeeQuadruple) 3190 { 3191 // Logarithm using log(x) = z + z^^3 R(z) / S(z), 3192 // where z = 2(x - 1)/(x + 1) 3193 if ((exp > 2) || (exp < -2)) 3194 { 3195 if (x < SQRT1_2) 3196 { // 2(2x - 1)/(2x + 1) 3197 exp -= 1; 3198 z = x - 0.5; 3199 y = 0.5 * z + 0.5; 3200 } 3201 else 3202 { // 2(x - 1)/(x + 1) 3203 z = x - 0.5; 3204 z -= 0.5; 3205 y = 0.5 * x + 0.5; 3206 } 3207 x = z / y; 3208 z = x * x; 3209 z = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); 3210 z += exp * C2; 3211 z += x; 3212 z += exp * C1; 3213 3214 return z; 3215 } 3216 } 3217 3218 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) 3219 if (x < SQRT1_2) 3220 { 3221 exp -= 1; 3222 x = 2.0 * x - 1.0; 3223 } 3224 else 3225 { 3226 x = x - 1.0; 3227 } 3228 z = x * x; 3229 static if (F.realFormat == RealFormat.ieeeSingle) 3230 y = x * (z * poly(x, coeffs.logP)); 3231 else 3232 y = x * (z * poly(x, coeffs.logP) / poly(x, coeffs.logQ)); 3233 y += exp * C2; 3234 z = y - 0.5 * z; 3235 3236 // Note, the sum of above terms does not exceed x/4, 3237 // so it contributes at most about 1/4 lsb to the error. 3238 z += x; 3239 z += exp * C1; 3240 3241 return z; 3242 } 3243 3244 /************************************** 3245 * Calculate the base-10 logarithm of x. 3246 * 3247 * $(TABLE_SV 3248 * $(TR $(TH x) $(TH log10(x)) $(TH divide by 0?) $(TH invalid?)) 3249 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) 3250 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes)) 3251 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) 3252 * ) 3253 */ 3254 pragma(inline, true) 3255 real log10(real x) @safe pure nothrow @nogc 3256 { 3257 version (INLINE_YL2X) 3258 { 3259 import std.math.constants : LOG2; 3260 return core.math.yl2x(x, LOG2); 3261 } 3262 else 3263 return log10Impl(x); 3264 } 3265 3266 /// ditto 3267 pragma(inline, true) 3268 double log10(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log10(cast(real) x) : log10Impl(x); } 3269 3270 /// ditto 3271 pragma(inline, true) 3272 float log10(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log10(cast(real) x) : log10Impl(x); } 3273 3274 // @@@DEPRECATED_[2.112.0]@@@ 3275 deprecated("`std.math.exponential.log10` called with argument types `(int)` matches both " 3276 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3277 real log10(int x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3278 // @@@DEPRECATED_[2.112.0]@@@ 3279 deprecated("`std.math.exponential.log10` called with argument types `(uint)` matches both " 3280 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3281 real log10(uint x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3282 // @@@DEPRECATED_[2.112.0]@@@ 3283 deprecated("`std.math.exponential.log10` called with argument types `(long)` matches both " 3284 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3285 real log10(long x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3286 // @@@DEPRECATED_[2.112.0]@@@ 3287 deprecated("`std.math.exponential.log10` called with argument types `(ulong)` matches both " 3288 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3289 real log10(ulong x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3290 3291 /// 3292 @safe pure nothrow @nogc unittest 3293 { 3294 import std.math.algebraic : fabs; 3295 3296 assert(fabs(log10(1000.0L) - 3) < .000001); 3297 } 3298 3299 private T log10Impl(T)(T x) @safe pure nothrow @nogc 3300 { 3301 import std.math.constants : SQRT1_2; 3302 import std.math.algebraic : poly; 3303 import std.math.traits : isNaN, isInfinity, signbit; 3304 import std.math : floatTraits, RealFormat; 3305 3306 alias coeffs = LogCoeffs!T; 3307 alias F = floatTraits!T; 3308 3309 static if (F.realFormat == RealFormat.ieeeExtended || 3310 F.realFormat == RealFormat.ieeeExtended53 || 3311 F.realFormat == RealFormat.ieeeQuadruple) 3312 { 3313 // log10(2) split into two parts. 3314 enum T L102A = 0.3125L; 3315 enum T L102B = -1.14700043360188047862611052755069732318101185E-2L; 3316 3317 // log10(e) split into two parts. 3318 enum T L10EA = 0.5L; 3319 enum T L10EB = -6.570551809674817234887108108339491770560299E-2L; 3320 } 3321 else static if (F.realFormat == RealFormat.ieeeDouble || 3322 F.realFormat == RealFormat.ieeeSingle) 3323 { 3324 enum T L102A = 3.0078125E-1; 3325 enum T L102B = 2.48745663981195213739E-4; 3326 3327 enum T L10EA = 4.3359375E-1; 3328 enum T L10EB = 7.00731903251827651129E-4; 3329 } 3330 else 3331 static assert(0, "Not implemented for this architecture"); 3332 3333 // Special cases are the same as for log. 3334 if (isNaN(x)) 3335 return x; 3336 if (isInfinity(x) && !signbit(x)) 3337 return x; 3338 if (x == 0.0) 3339 return -T.infinity; 3340 if (x < 0.0) 3341 return T.nan; 3342 3343 // Separate mantissa from exponent. 3344 // Note, frexp is used so that denormal numbers will be handled properly. 3345 T y, z; 3346 int exp; 3347 3348 x = frexp(x, exp); 3349 3350 static if (F.realFormat == RealFormat.ieeeExtended || 3351 F.realFormat == RealFormat.ieeeExtended53 || 3352 F.realFormat == RealFormat.ieeeQuadruple) 3353 { 3354 // Logarithm using log(x) = z + z^^3 R(z) / S(z), 3355 // where z = 2(x - 1)/(x + 1) 3356 if ((exp > 2) || (exp < -2)) 3357 { 3358 if (x < SQRT1_2) 3359 { // 2(2x - 1)/(2x + 1) 3360 exp -= 1; 3361 z = x - 0.5; 3362 y = 0.5 * z + 0.5; 3363 } 3364 else 3365 { // 2(x - 1)/(x + 1) 3366 z = x - 0.5; 3367 z -= 0.5; 3368 y = 0.5 * x + 0.5; 3369 } 3370 x = z / y; 3371 z = x * x; 3372 y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); 3373 goto Ldone; 3374 } 3375 } 3376 3377 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) 3378 if (x < SQRT1_2) 3379 { 3380 exp -= 1; 3381 x = 2.0 * x - 1.0; 3382 } 3383 else 3384 x = x - 1.0; 3385 3386 z = x * x; 3387 static if (F.realFormat == RealFormat.ieeeSingle) 3388 y = x * (z * poly(x, coeffs.log10P)); 3389 else 3390 y = x * (z * poly(x, coeffs.log10P) / poly(x, coeffs.log10Q)); 3391 y = y - 0.5 * z; 3392 3393 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). 3394 // This sequence of operations is critical and it may be horribly 3395 // defeated by some compiler optimizers. 3396 Ldone: 3397 z = y * L10EB; 3398 z += x * L10EB; 3399 z += exp * L102B; 3400 z += y * L10EA; 3401 z += x * L10EA; 3402 z += exp * L102A; 3403 3404 return z; 3405 } 3406 3407 /** 3408 * Calculates the natural logarithm of 1 + x. 3409 * 3410 * For very small x, log1p(x) will be more accurate than 3411 * log(1 + x). 3412 * 3413 * $(TABLE_SV 3414 * $(TR $(TH x) $(TH log1p(x)) $(TH divide by 0?) $(TH invalid?)) 3415 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) $(TD no)) 3416 * $(TR $(TD -1.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) 3417 * $(TR $(TD $(LT)-1.0) $(TD -$(NAN)) $(TD no) $(TD yes)) 3418 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) 3419 * ) 3420 */ 3421 pragma(inline, true) 3422 real log1p(real x) @safe pure nothrow @nogc 3423 { 3424 version (INLINE_YL2X) 3425 { 3426 // On x87, yl2xp1 is valid if and only if -0.5 <= lg(x) <= 0.5, 3427 // ie if -0.29 <= x <= 0.414 3428 import std.math.constants : LN2; 3429 return (core.math.fabs(x) <= 0.25) ? core.math.yl2xp1(x, LN2) : core.math.yl2x(x+1, LN2); 3430 } 3431 else 3432 return log1pImpl(x); 3433 } 3434 3435 /// ditto 3436 pragma(inline, true) 3437 double log1p(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log1p(cast(real) x) : log1pImpl(x); } 3438 3439 /// ditto 3440 pragma(inline, true) 3441 float log1p(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log1p(cast(real) x) : log1pImpl(x); } 3442 3443 // @@@DEPRECATED_[2.112.0]@@@ 3444 deprecated("`std.math.exponential.log1p` called with argument types `(int)` matches both " 3445 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3446 real log1p(int x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3447 // @@@DEPRECATED_[2.112.0]@@@ 3448 deprecated("`std.math.exponential.log1p` called with argument types `(uint)` matches both " 3449 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3450 real log1p(uint x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3451 // @@@DEPRECATED_[2.112.0]@@@ 3452 deprecated("`std.math.exponential.log1p` called with argument types `(long)` matches both " 3453 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3454 real log1p(long x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3455 // @@@DEPRECATED_[2.112.0]@@@ 3456 deprecated("`std.math.exponential.log1p` called with argument types `(ulong)` matches both " 3457 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3458 real log1p(ulong x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3459 3460 /// 3461 @safe pure unittest 3462 { 3463 import std.math.traits : isIdentical, isNaN; 3464 import std.math.operations : feqrel; 3465 3466 assert(isIdentical(log1p(0.0), 0.0)); 3467 assert(log1p(1.0).feqrel(0.69314) > 16); 3468 3469 assert(log1p(-1.0) == -real.infinity); 3470 assert(isNaN(log1p(-2.0))); 3471 assert(log1p(real.nan) is real.nan); 3472 assert(log1p(-real.nan) is -real.nan); 3473 assert(log1p(real.infinity) == real.infinity); 3474 } 3475 3476 private T log1pImpl(T)(T x) @safe pure nothrow @nogc 3477 { 3478 import std.math.traits : isNaN, isInfinity, signbit; 3479 3480 // Special cases. 3481 if (isNaN(x) || x == 0.0) 3482 return x; 3483 if (isInfinity(x) && !signbit(x)) 3484 return x; 3485 if (x == -1.0) 3486 return -T.infinity; 3487 if (x < -1.0) 3488 return T.nan; 3489 3490 return logImpl(x + 1.0); 3491 } 3492 3493 /*************************************** 3494 * Calculates the base-2 logarithm of x: 3495 * $(SUB log, 2)x 3496 * 3497 * $(TABLE_SV 3498 * $(TR $(TH x) $(TH log2(x)) $(TH divide by 0?) $(TH invalid?)) 3499 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no) ) 3500 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes) ) 3501 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no) ) 3502 * ) 3503 */ 3504 pragma(inline, true) 3505 real log2(real x) @safe pure nothrow @nogc 3506 { 3507 version (INLINE_YL2X) 3508 return core.math.yl2x(x, 1.0L); 3509 else 3510 return log2Impl(x); 3511 } 3512 3513 /// ditto 3514 pragma(inline, true) 3515 double log2(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log2(cast(real) x) : log2Impl(x); } 3516 3517 /// ditto 3518 pragma(inline, true) 3519 float log2(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log2(cast(real) x) : log2Impl(x); } 3520 3521 // @@@DEPRECATED_[2.112.0]@@@ 3522 deprecated("`std.math.exponential.log2` called with argument types `(int)` matches both " 3523 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3524 real log2(int x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3525 // @@@DEPRECATED_[2.112.0]@@@ 3526 deprecated("`std.math.exponential.log2` called with argument types `(uint)` matches both " 3527 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3528 real log2(uint x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3529 // @@@DEPRECATED_[2.112.0]@@@ 3530 deprecated("`std.math.exponential.log2` called with argument types `(long)` matches both " 3531 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3532 real log2(long x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3533 // @@@DEPRECATED_[2.112.0]@@@ 3534 deprecated("`std.math.exponential.log2` called with argument types `(ulong)` matches both " 3535 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3536 real log2(ulong x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3537 3538 /// 3539 @safe unittest 3540 { 3541 import std.math.operations : isClose; 3542 3543 assert(isClose(log2(1024.0L), 10)); 3544 } 3545 3546 @safe @nogc nothrow unittest 3547 { 3548 import std.math.operations : isClose; 3549 3550 // check if values are equal to 19 decimal digits of precision 3551 assert(isClose(log2(1024.0L), 10, 1e-18)); 3552 } 3553 3554 private T log2Impl(T)(T x) @safe pure nothrow @nogc 3555 { 3556 import std.math.traits : isNaN, isInfinity, signbit; 3557 import std.math.constants : SQRT1_2, LOG2E; 3558 import std.math.algebraic : poly; 3559 import std.math : floatTraits, RealFormat; 3560 3561 alias coeffs = LogCoeffs!T; 3562 alias F = floatTraits!T; 3563 3564 // Special cases are the same as for log. 3565 if (isNaN(x)) 3566 return x; 3567 if (isInfinity(x) && !signbit(x)) 3568 return x; 3569 if (x == 0.0) 3570 return -T.infinity; 3571 if (x < 0.0) 3572 return T.nan; 3573 3574 // Separate mantissa from exponent. 3575 // Note, frexp is used so that denormal numbers will be handled properly. 3576 T y, z; 3577 int exp; 3578 3579 x = frexp(x, exp); 3580 3581 static if (F.realFormat == RealFormat.ieeeDouble || 3582 F.realFormat == RealFormat.ieeeExtended || 3583 F.realFormat == RealFormat.ieeeExtended53 || 3584 F.realFormat == RealFormat.ieeeQuadruple) 3585 { 3586 // Logarithm using log(x) = z + z^^3 R(z) / S(z), 3587 // where z = 2(x - 1)/(x + 1) 3588 if ((exp > 2) || (exp < -2)) 3589 { 3590 if (x < SQRT1_2) 3591 { // 2(2x - 1)/(2x + 1) 3592 exp -= 1; 3593 z = x - 0.5; 3594 y = 0.5 * z + 0.5; 3595 } 3596 else 3597 { // 2(x - 1)/(x + 1) 3598 z = x - 0.5; 3599 z -= 0.5; 3600 y = 0.5 * x + 0.5; 3601 } 3602 x = z / y; 3603 z = x * x; 3604 y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); 3605 goto Ldone; 3606 } 3607 } 3608 3609 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) 3610 if (x < SQRT1_2) 3611 { 3612 exp -= 1; 3613 x = 2.0 * x - 1.0; 3614 } 3615 else 3616 x = x - 1.0; 3617 3618 z = x * x; 3619 static if (F.realFormat == RealFormat.ieeeSingle) 3620 y = x * (z * poly(x, coeffs.log2P)); 3621 else 3622 y = x * (z * poly(x, coeffs.log2P) / poly(x, coeffs.log2Q)); 3623 y = y - 0.5 * z; 3624 3625 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). 3626 // This sequence of operations is critical and it may be horribly 3627 // defeated by some compiler optimizers. 3628 Ldone: 3629 z = y * (LOG2E - 1.0); 3630 z += x * (LOG2E - 1.0); 3631 z += y; 3632 z += x; 3633 z += exp; 3634 3635 return z; 3636 } 3637 3638 /***************************************** 3639 * Extracts the exponent of x as a signed integral value. 3640 * 3641 * If x is subnormal, it is treated as if it were normalized. 3642 * For a positive, finite x: 3643 * 3644 * 1 $(LT)= $(I x) * FLT_RADIX$(SUPERSCRIPT -logb(x)) $(LT) FLT_RADIX 3645 * 3646 * $(TABLE_SV 3647 * $(TR $(TH x) $(TH logb(x)) $(TH divide by 0?) ) 3648 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) $(TD no)) 3649 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) ) 3650 * ) 3651 */ 3652 pragma(inline, true) 3653 real logb(real x) @trusted pure nothrow @nogc 3654 { 3655 version (InlineAsm_X87_MSVC) 3656 return logbAsm(x); 3657 else 3658 return logbImpl(x); 3659 } 3660 3661 /// ditto 3662 pragma(inline, true) 3663 double logb(double x) @trusted pure nothrow @nogc { return logbImpl(x); } 3664 3665 /// ditto 3666 pragma(inline, true) 3667 float logb(float x) @trusted pure nothrow @nogc { return logbImpl(x); } 3668 3669 /// 3670 @safe @nogc nothrow unittest 3671 { 3672 assert(logb(1.0) == 0); 3673 assert(logb(100.0) == 6); 3674 3675 assert(logb(0.0) == -real.infinity); 3676 assert(logb(real.infinity) == real.infinity); 3677 assert(logb(-real.infinity) == real.infinity); 3678 } 3679 3680 @safe @nogc nothrow unittest 3681 { 3682 import std.meta : AliasSeq; 3683 import std.typecons : Tuple; 3684 import std.math.traits : isNaN; 3685 static foreach (F; AliasSeq!(float, double, real)) 3686 {{ 3687 alias T = Tuple!(F, F); 3688 T[17] vals = // x, logb(x) 3689 [ 3690 T(1.0 , 0 ), 3691 T(100.0 , 6 ), 3692 T(0.0 , -F.infinity), 3693 T(-0.0 , -F.infinity), 3694 T(1024 , 10 ), 3695 T(-2000 , 10 ), 3696 T(0x0.1p-127 , -131 ), 3697 T(0x0.01p-127 , -135 ), 3698 T(0x0.011p-127 , -135 ), 3699 T(F.nan , F.nan ), 3700 T(-F.nan , F.nan ), 3701 T(F.infinity , F.infinity ), 3702 T(-F.infinity , F.infinity ), 3703 T(F.min_normal , F.min_exp-1), 3704 T(-F.min_normal, F.min_exp-1), 3705 T(F.max , F.max_exp-1), 3706 T(-F.max , F.max_exp-1), 3707 ]; 3708 3709 foreach (elem; vals) 3710 { 3711 if (isNaN(elem[1])) 3712 assert(isNaN(logb(elem[1]))); 3713 else 3714 assert(logb(elem[0]) == elem[1]); 3715 } 3716 }} 3717 } 3718 3719 version (InlineAsm_X87_MSVC) 3720 private T logbAsm(T)(T x) @trusted pure nothrow @nogc 3721 { 3722 version (X86_64) 3723 { 3724 asm pure nothrow @nogc 3725 { 3726 naked ; 3727 fld real ptr [RCX] ; 3728 fxtract ; 3729 fstp ST(0) ; 3730 ret ; 3731 } 3732 } 3733 else 3734 { 3735 asm pure nothrow @nogc 3736 { 3737 fld x ; 3738 fxtract ; 3739 fstp ST(0) ; 3740 } 3741 } 3742 } 3743 3744 private T logbImpl(T)(T x) @trusted pure nothrow @nogc 3745 { 3746 import std.math.traits : isFinite; 3747 3748 // Handle special cases. 3749 if (!isFinite(x)) 3750 return x * x; 3751 if (x == 0) 3752 return -1 / (x * x); 3753 3754 return ilogb(x); 3755 } 3756 3757 /************************************* 3758 * Efficiently calculates x * 2$(SUPERSCRIPT n). 3759 * 3760 * scalbn handles underflow and overflow in 3761 * the same fashion as the basic arithmetic operators. 3762 * 3763 * $(TABLE_SV 3764 * $(TR $(TH x) $(TH scalb(x))) 3765 * $(TR $(TD $(PLUSMNINF)) $(TD $(PLUSMNINF)) ) 3766 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) ) 3767 * ) 3768 */ 3769 pragma(inline, true) 3770 real scalbn(real x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); } 3771 3772 /// ditto 3773 pragma(inline, true) 3774 double scalbn(double x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); } 3775 3776 /// ditto 3777 pragma(inline, true) 3778 float scalbn(float x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); } 3779 3780 /// 3781 @safe pure nothrow @nogc unittest 3782 { 3783 assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L); 3784 assert(scalbn(-real.infinity, 5) == -real.infinity); 3785 assert(scalbn(2.0,10) == 2048.0); 3786 assert(scalbn(2048.0f,-10) == 2.0f); 3787 } 3788 3789 pragma(inline, true) 3790 private F _scalbn(F)(F x, int n) 3791 { 3792 import std.math.traits : isInfinity; 3793 3794 if (__ctfe) 3795 { 3796 // Handle special cases. 3797 if (x == F(0.0) || isInfinity(x)) 3798 return x; 3799 } 3800 return core.math.ldexp(x, n); 3801 } 3802 3803 @safe pure nothrow @nogc unittest 3804 { 3805 // CTFE-able test 3806 static assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L); 3807 static assert(scalbn(-real.infinity, 5) == -real.infinity); 3808 // Test with large exponent delta n where the result is in bounds but 2.0L ^^ n is not. 3809 enum initialExponent = real.min_exp + 2, resultExponent = real.max_exp - 2; 3810 enum int n = resultExponent - initialExponent; 3811 enum real x = 0x1.2345678abcdefp0L * (2.0L ^^ initialExponent); 3812 enum staticResult = scalbn(x, n); 3813 static assert(staticResult == 0x1.2345678abcdefp0L * (2.0L ^^ resultExponent)); 3814 assert(scalbn(x, n) == staticResult); 3815 } 3816